Падение производительности при использовании 'where id IN [table]' с только 1 строкой в ​​[table]? - PullRequest
1 голос
/ 15 февраля 2009

У меня есть хранимая процедура, которая принимает строку идентификаторов, разделенных запятыми. Я разделяю их, помещаю во временную таблицу и извлекаю записи из другой таблицы, используя где id IN [table]

Можно ли использовать эту же процедуру, когда для параметра передается только один идентификатор? Я мог бы написать вторую хранимую процедуру, которая делала бы то же самое, но вместо этого делать , где id = @ id .

У меня есть МНОГИЕ хранимые процедуры, в которых можно передать несколько идентификаторов или только один. Пытаюсь ли я повторно использовать существующие процедуры или написать новые? Значительно ли выросла производительность?

Ответы [ 6 ]

2 голосов
/ 15 февраля 2009

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

Я бы посмотрел на производительность разбора строки, создания временной таблицы и вставки в временную таблицу. Если вы сделаете их максимально быстрыми, это окажет большее влияние на общую производительность, чем если бы вы использовали в или = для случая с одним предметом.

2 голосов
/ 15 февраля 2009

Возможно, вы захотите попробовать JOIN вместо WHERE id IN - хотя я думаю, что вы получите тот же план запроса.

Итак, я полагаю, вы делаете:

SELECT COl1, Col2, ...
FROM MyTable
WHERE id IN (SELECT id FROM @MyTempTable)

В этом случае эквивалентный синтаксис JOIN будет:

SELECT COl1, Col2, ...
FROM  MyTable AS T1
     JOIN @MyTempTable AS T2
         ON T2.id = T1.id

и во втором случае, будет ли 1 или много строк, это будет очень эффективно при условии индексации [id] (я предполагаю, что это PK в вашей таблице и используется кластерный индекс).

(Помните, что если в @MyTempTable у вас есть идентификаторы DUP, вы также получите дубликаты из MyTable :()

Для лучшей производительности стоило бы явно объявить [id] как PK в вашей временной таблице (но, учитывая, что он содержит только несколько строк, он, вероятно, не будет иметь больших шансов)

DECLARE @TempTable TABLE
(
    id int NOT NULL,
    PRIMARY KEY
    (
        id
    )
)
1 голос
/ 07 июня 2009

Когда вы создаете временную таблицу (не переменную таблицы), она имеет статистику. Таким образом, оптимизатор определит лучший план, и лучший план для одного идентификатора может быть таким же, как для 10 идентификаторов, но для идентификаторов 50 КБ он может выбрать другой план. Поэтому я не буду пытаться оптимизировать его, если у вас нет проблем с производительностью.

1 голос
/ 15 февраля 2009

Поскольку вы указали, что это список, разделенный запятыми, вы можете сделать что-то вроде этого в своем sproc:

IF (CHARINDEX(',', @id) = 0)
BEGIN
    -- the @id parameter contains a single value
    SELECT *
    FROM your_table
    WHERE id = @id  -- maybe need to cast @id if the column isn't a string
END
ELSE
BEGIN
    -- the @id parameter contains a comma-delimited list
    -- only perform the expensive splitting logic at this point
    -- eg, SET @yourTempTable = dbo.SplitCommaDelimitedIDsIntoTable(@id)
    SELECT *
    FROM your_table
    WHERE id IN (SELECT id FROM @yourTempTable)
END
1 голос
/ 15 февраля 2009

Как сказано в rde6173, выполните COUNT для временной таблицы, чтобы определить, какой запрос SELECT использовать.

1 голос
/ 15 февраля 2009

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

Есть хит производительности с IN; План выполнения должен подробно описать это для вас.

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