Я пытаюсь выяснить, почему запрос по одной таблице занимает намного больше времени, чем я думаю. Я уверен, что на этот вопрос есть простой ответ, но я уже некоторое время ломаю голову и, возможно, просто не вижу леса за деревьями.
У меня есть таблица шириной примерно в 35 столбцов, со стандартным ассортиментом столбцов (несколько int, куча varchar () размеров от 10 до 255, довольно базовый c), в котором я поместил кластерный индекс в столбец, давайте назовем «PackageID» для ради объяснения. В этой таблице немного севернее миллиона записей, так что есть большой объем данных, которые нужно пролистать, и может быть одна или несколько записей с одним и тем же PackageID из-за характера записей, но это всего лишь один «плоский» Таблица.
Попадание в таблицу У меня есть хранимая процедура, которая принимает аргумент varchar(max)
, который может быть единственным PackageID или это может быть список с разделителями-запятыми 10, 50, 500 или более. SPro c вызывает довольно стандартную простую функцию Split()
(найденную здесь и на других сайтах), которая разбивает список, возвращая значения в виде таблицы, которую я затем пытаюсь отфильтровать по таблице для результатов. Идентификаторы представляют собой целые значения в настоящее время длиной до 5 цифр, в будущем они будут расти, но сейчас только 5.
Я пробовал несколько вариантов запроса внутри SPro c (только запрос здесь для краткости):
SELECT PackageID, Column01, Column02, Column03, ... , ColumnN
FROM MyTable
WHERE PackageID IN (SELECT SplitValue FROM dbo.Split(@ListOfIDs, ','))
и
;WITH cteIDs AS (
SELECT SplitValue
FROM dbo.Split(@ListOfIDs, ',')
)
SELECT PackageID, Column01, Column02, Column03, ... , ColumnN
FROM MyTable m
INNER JOIN cteIDs c ON m.PackageID = c.SplitValue
Запуск из SSMS в обоих оценочных планах выполнения выглядит одинаково и занимает примерно одинаковое количество времени. Когда @ListOfIDs
короткий, записи возвращаются быстро, но по мере того, как список идентификаторов увеличивается (и может достигать сотен и более), время выполнения может go минут или дольше. Здесь нет триггеров, ничто другое не использует его, запрос не блокируется и не блокируется ничем, что я могу сказать ... он просто работает медленно.
Я чувствую, что здесь упускаю что-то безумно простое но я просто не вижу этого.
Спасибо за любую помощь, спасибо!
ОБНОВЛЕНИЕ
Это функция Split()
, которую я использую, это то, что я вытащил отсюда, я надеваю Не знаю, как долго go, и с тех пор использовал. Если есть лучший вариант, который я с удовольствием поменяю, этот просто сработал, поэтому я никогда не думал об этом ...
CREATE FUNCTION [dbo].[Split]
(
@String VARCHAR(max),
@Delimiter VARCHAR(5)
)
RETURNS @SplittedValues TABLE
(
OccurenceId SMALLINT IDENTITY(1,1),
SplitValue VARCHAR(max)
)
AS
BEGIN
DECLARE @SplitLength INT
WHILE LEN(@String) > 0
BEGIN
SELECT @SplitLength = (CASE CHARINDEX(@Delimiter, @String)
WHEN 0 THEN LEN(@String)
ELSE CHARINDEX(@Delimiter, @String) -1
END)
INSERT INTO @SplittedValues
SELECT SUBSTRING(@String, 1, @SplitLength)
SELECT @String = (CASE (LEN(@String) - @SplitLength)
WHEN 0 THEN ''
ELSE RIGHT(@String, LEN(@String) - @SplitLength - 1)
END)
END
RETURN
END
GO
ОБНОВЛЕНИЕ - Тестирование предложений комментариев
Я попытался опробовать предложения в комментариях, и вот что я обнаружил ...
- Размер таблицы: 1 081 154 записей
- Уникальный счетчик "PackageID" : 16008 ID
- Размер теста списка: 500 случайных идентификаторов (ввод аргументов строки через запятую)
Когда я запускаю (в SSMS) запрос, используя только функцию Split()
, он принимает в среднем 309 секунд, чтобы вернуть 373 761 запись.
Когда я запускаю запрос, но сначала выкидываю результаты Split()
в таблицу @TempTable (с индексом первичного ключа) и соединяю ее с таблицей, это занимает в среднем 111 секунд, чтобы вернуть те же 373 761 записей.
Я понимаю, что это много записей, но это плоская таблица с кластеризованным индексом на PackageID. Запрос является очень простым c, просто запрашивая совпадения записей по идентификатору. Здесь нет ни вычислений, ни обработки, ни других соединений с другими таблицами, операторов CASE, группировок, имущих и т. Д. c. Я не понимаю, почему выполнение запроса занимает так много времени. Я видел, как другие запросы с огромной логикой c возвращали тысячи записей в секунду, почему эта «простая» вещь застряла?
ОБНОВЛЕНИЕ - Добавление Exe c Plan
В соответствии с запросом приведен план выполнения запроса, который я выполняю. После выгрузки разделенных значений входящего списка идентификаторов с разделителями в @TempTable запрос просто запрашивает все записи из таблицы A («MyTable») с совпадающими идентификаторами, найденными в таблице B (@TempTable). Вот и все.
Обновление - Заказ по
В прилагаемом Плане выполнения, отмеченном в комментариях, присутствовал ORDER BY, который, по-видимому, потреблял значительную сумму накладных расходов. Я удалил это из своего запроса и повторно запустил свои тесты, что привело к минимальному улучшению времени выполнения. На тестовом прогоне, который ранее занимал 7 минут, без ORDER BY будет завершено в 6:30 до 6:45 минут.
На этом этапе игры я собираюсь объяснить это объемом данных, а не всем, что связано с самим запросом. Это может быть что-то в нашей сети, количество прыжков, через которые должны пройти данные между SQL Сервером и пунктом назначения, скорость соединения с конечным пользователем и / или любое количество других факторов, не зависящих от меня или не зависящих от меня. что-нибудь о.
Спасибо всем, кто откликнулся и предоставил предложения. Многие из них я буду использовать в дальнейшем, и буду иметь в виду, работая с базой данных.