Почему тег запроса «IN» стоит так дорого в хранимых процедурах sql? - PullRequest
0 голосов
/ 13 июня 2019

Как я могу улучшить мою проблему с производительностью? У меня есть SQL-запрос с «IN», я думаю, «IN» делает некоторые проблемы с производительностью. Но мне нужен индекс моего sql запроса?

Мой sql запрос:


SELECT [p].[ReferencedxxxId]  
FROM [Common].[xxxReference] AS [p]  
WHERE ([p].[IsDeleted] = 0)  
  AND (([p].[ReferencedxyzType] = @__refxyzType_0)
  AND [p].[ReferencedxxxId] IN ('42342','ffsdfd','5345345345'))

Мое решение: (НО НУЖНА ВАША ПОМОЩЬ ДЛЯ ЛУЧШЕГО СОВЕТА) Какой из них является правильным кластерным или некластерным индексом?

USE [xxx]
GO
CREATE NONCLUSTERED INDEX IX_NonClusteredIndexDemo_xxxId
ON [Common].[xxxReference](xxxId)
INCLUDE ([ID],[ReferencedxxxId])
WITH (DROP_EXISTING=ON, ONLINE=ON, FILLFACTOR=90)
GO

Второе:

CREATE INDEX xxxReference_ReferencedxxxId_index
ON [Common].[xxxReference]  (ReferencedxxxId)[/code]

Какой из них правильный или у вас есть лучшее решение?

Ответы [ 3 ]

3 голосов
/ 13 июня 2019

Проблема производительности этого запроса не является результатом использования оператора IN.
Этот оператор очень хорошо работает с небольшими списками (скажем, менее 1000 членов).

Бутылка производительностиЗдесь дело в том, что SQL Server выполняет сканирование по индексу вместо поиска по индексу (что очень дорого) и поиск по ключу, который составляет 20% от стоимости запроса.

Чтобы избежать обеих проблем,можно добавить индекс для IsDeleted, ReferencedxyzType и ReferencedxxxId - вероятно, в этом точном порядке.

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

Поэтому я предлагаю следующее: не пытайтесь решить эту проблему самостоятельно с помощью незнакомцев в Интернете.,На несколько часов / дней найдите эксперта на консультационную работу, чтобы проанализировать систему и помочь вам настроить ее.
Узнайте все, что сможете во время этого процесса.Задавайте вопросы обо всем, что не тривиально.Это будут хорошо потраченные деньги.

2 голосов
/ 13 июня 2019

Пара вещей:

  1. Если у вас есть оператор SELECT внутри IN, этого следует избегать и должен быть заменен предложением EXISTS. Но по вашему выше Например, это не имеет значения, поскольку у вас есть прямые значения внутри IN.

    Использование EXISTS и NOT EXISTS вместо IN и NOT IN помогает SQL Серверу не нужно сканировать каждое значение столбца для каждого значения внутри IN / NOT IN и, скорее, могут закорачивать искать один раз совпадение или несоответствие найдено.

  2. Избегайте неявного преобразования. Они ухудшают производительность из-за много причин, в том числе и я> SQL Server не удалось найти правильный статистика по индексу и, следовательно, не в состоянии использовать индекс и предпочел бы использовать кластерный индекс, доступный в таблице (который может не покрывать ваш запрос), ii> Не назначить правильное требуемая оперативная память на этапе выделения памяти для запроса по хранилищу двигатель, iii> Оценка мощности становится неправильной как SQL Server не будет статистики по вычисленному значению этого столбца, и скорее всего, была статистика по этому столбцу.

    Если вы посмотрите на свой план выполнения, опубликованный выше, вы увидите желтая отметка в вашем «SELECT». Если вы наведите курсор мыши на него, вы увидите одно / несколько предупреждающих сообщений. Если ваше предупреждение связано с неявным преобразования, попробуйте использовать правильные типы данных во время сравнения.

    Например. Каков тип данных столбца '[ReferencedxxxId]'? Если оно это не NVARCHAR, а скорее VARCHAR, тогда я бы предложил:

  3. Сделайте значения внутри IN как VARCHAR (в настоящее время вы делаете их NVARCHAR). Таким образом, вы по-прежнему сможете в полной мере использовать индекс хранилища строк, созданный в столбце [ReferencedxxxId].

  4. Если вы должны иметь значения как NVARCHAR внутри предложения IN, тогда вам следует:

    • CONVERT / CAST столбец [ReferencedxxxId] в предложении IN. Это избавит от неявного преобразования, но вы больше не сможете в полной мере использовать индекс хранилища строк в столбце [ReferencedxxxId].

      +

    • Вместо этого создайте кластеризованный / некластеризованный индекс columnstore в таблице, охватывающий столбцы, используемые в запросе. Это должно значительно повысить производительность вашего запроса SELECT.

  5. Если вы решили пойти по пути использования индекса хранилища строк, исправив значения внутри IN, вам необходимо убедиться, что вы создали кластеризованный / некластеризованный индекс, который покрывает запрос. Это означает, что индекс охватывает столбцы, по которым выполняется поиск ([ReferencedxxxId], [ReferencedxxxType], [IsDeleted]), а затем включает столбцы, используемые в операторе SELECT в предложении INCLUDE (если это некластеризованный индекс)

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

0 голосов
/ 13 июня 2019

Исходя из предположения, что система на основе OLTP, а не OLAP, моим первым проходом будет индекс NC - учитывая, что isDeleted, вероятно, будет иметь наименьшую селективность, я бы поставил его последним, первый проход - индексом NC ReferencedxyzType, ReferencedxxxId, IsDeleted

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

Очевидно, что в таблице уже есть кластеризованный индекс (из плана запроса мы видим его), у нас нет сведений о том, что в нем.

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

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