Является ли длинное предложение IN запахом кода? - PullRequest
8 голосов
/ 02 июня 2011

Простой вопрос. Хотите знать, если длинное предложение IN является запахом кода? Я действительно не знаю, как это оправдать. Я не могу понять, почему пахнет иначе, чем я думаю.

select
  name,
  code,
  capital,
  population,
  flower,
  bird
from us_states
where
  code in
    ('NJ', 'NY', 'PA', 'CA', 'AL', 'AK', 'AZ',
    'IL', 'IN', 'KY', 'KS', 'DC', 'MD', 'MA')

Как база данных обычно реализует такой поиск? Временный стол сделан и присоединен к? Или это просто расширено на серию логических ИЛИ?

Такое ощущение, что это должно было быть соединение ...

Я не говорю, что все предложения IN плохие. Иногда вы не можете с этим поделать. Но есть некоторые случаи (особенно, чем дольше они получают), когда набор элементов, с которыми вы сопоставляете, фактически откуда-то приходит. И разве к этому нельзя присоединиться?

Стоит ли создавать (через уровень приложения) временную таблицу, в которой есть все элементы, по которым вы хотите выполнить поиск, а затем выполнять реальное соединение с этим?

select u.*
from us_states u

join #chosen_states t
on u.code = t.code

Ответы [ 5 ]

8 голосов
/ 02 июня 2011

Я думаю, что это запах кода.С одной стороны, базы данных имеют ограничения по количеству элементов, разрешенных в предложении IN, и если ваш SQL генерируется динамически, вы можете в конечном итоге увеличить эти ограничения.

Когда список начинает становитьсяДавно, я бы предпочел использовать хранимую процедуру с временной таблицей, чтобы избежать какой-либо вероятности ошибок.

Я сомневаюсь, что производительность является серьезной проблемой, хотя предложения IN очень быстрые, так как они могуткороткое замыкание, в отличие от NOT IN пунктов.

4 голосов
/ 02 июня 2011

Стоит ли создавать (через уровень приложения) временную таблицу.

Проблема с IN заключается в том, что он не использует индекс, и сравнение (наихудший случай: x14 здесь) повторяется для каждой строки в исходной таблице.

Хорошей идеей будет создание временной таблицы, если вы поместите индекс в поля объединения.
Таким образом, запрос может искать значение напрямую, используя индекс BTree, который должен принимать только 3 или 4 сравнения, худший случай log2 (14) = 3.something
Который намного быстрее.

Если вы сообразительны, вы даже можете использовать hash-index, и в этом случае БД требуется только 1 сравнение, что ускоряет ваш запрос в 3 раза по сравнению с индексом btree.

Советы по использованию временной таблицы
Обязательно используйте таблицу памяти
Используйте hash index в качестве основного ключа.
Попробуйте сделать вставки в одном утверждении.

Полупостоянное время, которое вы потратите на создание временной таблицы, будет уменьшено ускорением из-за времени поиска O (1) с использованием хэш-индекса.

0 голосов
/ 05 июля 2011

Я тоже считаю это «запахом». Предложение IN может, для случайного наблюдателя, напоминать набор, список, сумку, стол и т. Д., Но это не так.

В соответствии со стандартами SQL ваше предложение IN является просто синтаксическим сахаром для

(
 code = 'NJ' OR code = 'NY' OR code = 'PA' OR code = 'CA' 
    OR code = 'AL' OR code = 'AK' OR code = 'AZ' 
    OR code = 'IL' OR code = 'IN' OR code = 'KY' 
    OR code = 'KS' OR code = 'DC' OR code = 'MD' 
    OR code = 'MA'
)

Я бы ожидал, что типичный парсер расширит предложение IN именно таким образом; Я знаю, что SQL Server делает это, потому что красивые, аккуратные предложения IN, которые я использую для создания определенных ограничений CHECK, становятся ужасным набором предложений OR, когда я проверяю определение ограничения в INFORMATION_SCHEMA. YMMV: если вы беспокоитесь о производительности, протестируйте.

Существует практическое правило, в котором говорится, что если набор значений мал и стабилен, используйте предложение IN, в противном случае используйте таблицу. Является ли 14 из 52 «маленьким», субъективно. Будет ли небольшая таблица лучше проиндексирована, может зависеть от того, как она объединена с другими таблицами: этот вопрос SO может быть полезной ссылкой.

0 голосов
/ 02 июня 2011

Вы также можете использовать подзапрос с IN, как описано здесь в руководстве .

SELECT * FROM us_states WHERE code IN (SELECT code FROM state_codes);
0 голосов
/ 02 июня 2011

Я не знаю, что это запах кода, точно. Иногда у вас просто длинный список вещей in, которые могут существовать в вашем состоянии.

Что касается создания временной таблицы (или даже таблицы поиска) с элементами и объединения (или даже выполнения where [column] in (select [lookup] from [lookuptable]), то это один из моих предпочтительных методов IFF * a) Существует большое количество значений, которые b) будет меняться редко, если когда-либо.

*: «Если и только если»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...