SQL Query работает быстро с 19 элементами в предложении «IN» - намного медленнее с 20. Почему? - PullRequest
4 голосов
/ 02 декабря 2009

У меня есть запрос, который включает это:

... AND Record.RecordID IN (1,2,3,10,11,12,13,16,17,18,26,27,28,557,31,32,33,36,37,93) AND ...

Проблема заключается в том, что если в этом списке 20 или более элементов, выполнение запроса занимает более 25 секунд. Если их меньше 20, он выполняется немедленно. Есть идеи по оптимизации?

Ответы [ 7 ]

9 голосов
/ 02 декабря 2009

Поместите RecordID во временную таблицу и используйте inner join для фильтрации по ним. Для SQL Server это выглядит так:

declare @RecordIds table (int RecordID)
insert into @RecordIds values (1)
insert into @RecordIds values (2)
...
insert into @RecordIds values (93)

select r.*
from Records r
inner join @RecordIds ri on ri.RecordID = r.RecordID
9 голосов
/ 02 декабря 2009

Одна вещь, которую нужно сделать, это посмотреть на план оптимизатора (если вы можете) и увидеть, как план отличается, когда вы используете 20 или меньше элементов против> 20. В Oracle, например, вы можете использовать план объяснения Команда, чтобы увидеть этот вывод.

Вот некоторая информация о том, как использовать план объяснения в Oracle: http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/ex_plan.htm

Другие вопросы, которые необходимо учитывать, это наличие у вас индекса RecordID. Может случиться так, что после того, как вы превысите определенный порог (> 20 элементов в вашем случае), оптимизатор решит, что лучше использовать полное сканирование таблицы, чем использовать ваш индекс.

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

Вот ссылка на подсказки оптимизатора, которую вы можете прочитать: http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/hintsref.htm

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

2 голосов
/ 02 декабря 2009

Случай с 20-м пунктом перевешивает баланс этой конкретной оценки стоимости запроса от одного плана к другому. с 20 предметами вы, вероятно, получаете полное сканирование таблицы. IN - это просто синтаксический сахар для ИЛИ .. ИЛИ ... ИЛИ ... ИЛИ. ИЛИ - враг хороших планов запросов. Используйте соединение, как предложил Андомар.

Обновление

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

0 голосов
/ 07 декабря 2009

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

Проверьте план выполнения (CTRL-L) обоих запросов. Это единственный способ узнать, почему на это уходит больше времени, если в списке более 20 элементов.

Перед проверкой планов выполнения обновите статистику своей таблицы:

UPDATE STATISTICS records

если можешь подождать

UPDATE STATISTICS records WITH FULLSCAN

Второй займет больше времени, но у вас будет более согласованная статистика.

0 голосов
/ 02 декабря 2009

Табличная функция CLR могла бы стать другим способом создания таблицы на основе предоставленных параметров - для получения дополнительной информации см. SQL Server 2005: Табличные функции CLR

0 голосов
/ 02 декабря 2009

для MySQL руководство гласит: «Количество значений в списке IN ограничено только значением max_allowed_packet ». Кажется маловероятным, что это проблема, но место для поиска.

В любом случае сохранение значений IN() во временной таблице и присоединение к ней вашего запроса должно обойти всю проблему.

0 голосов
/ 02 декабря 2009

Это кажется грязным и ненужным, но вы пробовали:

(Record.RecordID IN (--19 items--) OR Record.RecordID = 20th_item) AND

Я не знаю, почему добавление 20-го элемента в группу IN подтолкнуло его за край.

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