Является ли WHERE ID IN (1, 2, 3, 4, 5, ...) наиболее эффективным? - PullRequest
15 голосов
/ 06 октября 2009

Я знаю, что эта тема была забита до смерти, но, похоже, многие статьи в Интернете часто ищут самый элегантный способ, а не самый эффективный способ его решения. Здесь проблема. Мы создаем приложение, в котором один из общих запросов к базе данных будет включать манипуляции (SELECT и UPDATE) на основе предоставленного пользователем списка идентификаторов. Ожидается, что рассматриваемая таблица будет иметь сотни тысяч строк, и предоставленные пользователем списки идентификаторов могут быть неограниченными, но, скорее всего, они будут десятки или сотни (мы можем ограничить ее по соображениям производительности позже).

Если мое понимание работы баз данных в целом правильное, то наиболее эффективным является простое использование конструкции WHERE ID IN (1, 2, 3, 4, 5, ...) и динамическое построение запросов. Суть проблемы заключается в том, что входные списки идентификаторов будут действительно произвольными, и поэтому независимо от того, насколько умна база данных или насколько умно мы ее реализуем, у нас всегда есть случайное подмножество целых чисел, с которого нужно начинать, и в конечном итоге каждый подход должен внутренне сводиться к чему-то вроде WHERE ID IN (1, 2, 3, 4, 5, ...) в любом случае.

В Интернете можно найти множество подходов. Например, один включает объявление табличной переменной, передачу списка идентификаторов в процедуру хранения в виде строки с разделителями-запятыми, разделение ее в процедуре сохранения, вставку идентификаторов в переменную таблицы и присоединение к ней основной таблицы, то есть что-то вроде это:

-- 1. Temporary table for ID’s:
DECLARE @IDS TABLE (ID int);

-- 2. Split the given string of ID’s, and each ID to @IDS.
-- Omitted for brevity.

-- 3. Join the main table to @ID’s:
SELECT MyTable.ID, MyTable.SomeColumn
FROM MyTable INNER JOIN @IDS ON MyTable.ID = @IDS.ID;

Если оставить в стороне проблемы с манипулированием строками, я думаю, что в этом случае, по сути, происходит то, что на третьем этапе SQL Server говорит: «Спасибо, это хорошо, но мне просто нужен список идентификаторов», и это сканирует табличную переменную @IDS, а затем n ищет в MyTable, где n - это число идентификаторов. Я провел некоторые элементарные оценки производительности и проверил план запросов, и, похоже, именно это и происходит. Таким образом, переменная таблицы, конкатенация и разбиение строк и все дополнительные INSERT не имеют смысла.

Я прав? Или я что-то упустил? Есть ли действительно какой-нибудь умный и более эффективный способ? По сути, я хочу сказать, что SQL Server должен выполнить n поиска индекса независимо от того, что и, и формулировка запроса как WHERE ID IN (1, 2, 3, 4, 5, ...) является наиболее простым способом его запросить.

Ответы [ 12 ]

0 голосов
/ 06 октября 2009

Если проблемы со строковыми манипуляциями будут отложены, я думаю, что:

ГДЕ ИД = 1 ИЛИ ИД = 2 ИЛИ ИД = 3 ...

более эффективен, но я бы этого не сделал.

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

0 голосов
/ 06 октября 2009

В течение многих лет я использую 3 подхода, но когда я начинаю использовать OR / M, это кажется ненужным.

Даже загрузка каждой строки по id не так неэффективна, как кажется.

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