2011-10-12 3 views
0

Я просто заметил, что мой запрос:Как переписать запрос в соответствии с CLUSTERED INDEX?

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 на колонке 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

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

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

SELECT MIN(myCol), MAX(myCol) 

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

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

+0

+1 Спасибо. Эти ссылки были полезны! Тогда я буду придерживаться этого. Мне было интересно - есть ли компактный способ написания этого запроса (например, использование CTE или что-то в этом роде), или я должен повторить свой запрос дважды? – Legend

+0

Вам не нужно делать это с помощью MS SQL Server.Я вижу, что обе эти статьи были для Oracle, когда я делаю min и max в большой (174-миллиметровой строке) таблице в SQL Server, в плане запроса показаны два пути выполнения и почти сразу получается результат. –

+0

@JasonGoemaat OP указал, что это не был его фактический запрос. Не проверяя фактический план запроса, нет хорошего способа убедиться, эффективно ли он использует индексы. Возможно ли, что MSSQL можно отговорить от использования индекса из-за какой-то странной структуры запросов. – Matthew

1

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

UPDATE STATISTICS TableB 

Вы также можете попробовать использовать optimizer hint:

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) 

Вы можете увидеть, что индексы используются с помощью «Display Предполагаемый план выполнения» в меню запроса (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) 
Смежные вопросы