Как мне переписать запрос, чтобы он соответствовал КЛАСТЕРНОМУ ИНДЕКСУ? - PullRequest
0 голосов
/ 13 октября 2011

Я только что заметил, что мой запрос:

SELECT X.A, X.B, X.GroupName
FROM TableA X
INNER JOIN TableB Y -- Huge table
ON (X.A = Y.Name OR X.B = Y.Name)

TableB имеет столбец CLUSTERED INDEX ON Name, из-за которого на выполнение этого запроса уходили часы. Поэтому я переписал запрос следующим образом:

SELECT X.A, X.B, X.GroupName
FROM TableA X
INNER JOIN TableB Y -- Huge table
ON X.A = Y.Name
UNION
SELECT X.A, X.B, X.GroupName
FROM TableA X
INNER JOIN TableB Y -- Huge table
ON X.B = Y.Name

Этот выполняется за несколько секунд или, в худшем случае, за минуты. Хотя теперь я понимаю причину, после того, как сжег себя, мне было интересно, есть ли более чистый способ написания этого запроса. Я думал о CTE, но тогда ON X.A = Y.Name и ON X.B = Y.Name подобны параметрам, и я не уверен, что с этим делать.

Мой фактический запрос очень большой, поэтому я хочу не повторять его два раза ради UNION. Есть предложения?

Ответы [ 2 ]

2 голосов
/ 13 октября 2011

В таких случаях может быть приемлемо использовать UNION, если два условия требуют использования индекса по-разному. Поместив их как OR в одно условие, вы можете исключить возможность использования индекса.

Это то же самое, что и проблема:

SELECT MIN(myCol), MAX(myCol)

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

Вот (устаревшая) ссылка, которая иллюстрирует мою точку зрения:
http://code.cheesydesign.com/?p=279
http://richardfoote.wordpress.com/category/index-full-scan-minmax/

1 голос
/ 13 октября 2011

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

UPDATE STATISTICS TableB

Вы также можетепопробуйте использовать подсказку оптимизатора :

SELECT X.A, X.B, X.GroupName
FROM TableA X
INNER JOIN TableB Y WITH (INDEX(ClusteredIndexName)) -- Huge table
ON (X.A = Y.Name OR X.B = Y.Name)

. Вы можете увидеть, какие индексы используются, используя «Показать предполагаемый план выполнения» в меню запроса (CTRL + L вместо CTRL + E).), но редко фактический запрос будет настроен по-другому.

Я бы также рекомендовал подсказку NOLOCK.Обычные запросы устанавливают общую блокировку данных, к которым они получают доступ, предотвращая обновление этих строк.С этой блокировкой также связаны некоторые накладные расходы.Использование NOLOCK может ускорить ваш запрос и увеличить параллелизм, но может привести к грязному чтению.Допустим, одна из этих строк в вашем большом запросе обновляется в середине его выполнения.Вы можете получить как старые, так и новые строки в ваших результатах (я думаю, никогда не видел, чтобы это произошло).Если вы не используете NOLOCK, это обновление может блокироваться до тех пор, пока ваш запрос не будет завершен, что может привести к превышению времени ожидания важного обновления.

SELECT X.A, X.B, X.GroupName
FROM TableA X WITH (NOLOCK)
INNER JOIN TableB Y WITH (NOLOCK, INDEX(ClusteredIndexName)) -- Huge table
ON (X.A = Y.Name OR X.B = Y.Name)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...