Это простой выбор из временной таблицы, оставляющий присоединение к существующей таблице по его первичному ключу, с двумя подвыборками, использующими top 1 со ссылкой на объединенную таблицу.
В коде:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Это точная копия моего запроса.
Если я удаляю два суб-выбора, он работает просто отлично и быстро. С двумя вложенными выборками я получаю около 100 записей в секунду, что крайне медленно для этого запроса, поскольку он должен возвращать почти миллион записей.
Я проверил, есть ли у каждой таблицы первичный ключ, все они имеют. Все они имеют индексы И статистику для своих важных столбцов, например, в этих предложениях WHERE и в предложениях JOIN. Единственная таблица, для которой не определен ни первичный ключ, ни индекс, является временной таблицей, но это не проблема, потому что она не связана с медленным суб-выбором, и, как я уже говорил, без суб-выбора она работает просто отлично.
Без них TOP 1
он возвращает более одного результата и выдает ошибку.
Помогите кому-нибудь?
РЕДАКТИРОВАТЬ :
Таким образом, план выполнения сказал мне, что я пропустил Индекс. Я создал его и пересоздал некоторые другие индексы. Через некоторое время план выполнения использовал их, и теперь запрос выполняется быстро. Единственная проблема в том, что мне не удалось сделать это снова на другом сервере, для того же запроса. Так что моим решением будет HINT, какой индекс будет использовать SQL Server.
Ответы:
Я думаю, что в запросе на миллион записей вы должны избегать подобных вещей
OUTER JOINS
. Я предлагаю вам использоватьUNION ALL
вместоLEFT JOIN
. Пока я думаю, чтоCROSS APPLY
это более эффективно, чем подзапрос в предложении select, я буду модифицировать запрос, написанный Conard Frix, что я считаю правильным.Сейчас: когда я начал изменять ваш запрос , я заметил , что у вас есть ИНЕКЕ говоря:
JoinedTable.WhereColumn IN (1, 3)
. в этом случае, если поле равно нулю, условие станет ложным. тогда почему вы используете LEFT JOIN при фильтрации строк с нулевым значением? Просто заменитеLEFT JOIN
СINNER JOIN
, я гарантирую, что это станет быстрее.о ИНДЕКС:
обратите внимание, что когда у вас есть индекс в таблице, скажем,
и ваш индекс:
и вы хотите сделать что-то вроде этого:
в свой индекс вы не включили столбец,
b
так что происходит?Если sql-сервер использует ваш индекс, ему придется искать в индексе, называемом «Index Seek», а затем обращаться к основной таблице, чтобы получить столбец
b
, который называется «Look Up» . Эта процедура может занять гораздо больше времени, чем сканирование самой таблицы: «Сканирование таблицы» .но основываясь на статистике, которую имеет sql-сервер, в таких ситуациях он может вообще не использовать ваш индекс.
поэтому прежде всего проверьте, используется
Execution Plan
ли индекс вообще.если да или нет и то и другое, измените свой индекс, чтобы включить все выбранные столбцы. скажи как:
в этом случае поиск не понадобится, и ваш запрос будет выполняться намного быстрее.
источник
Это суб выбирает в вашем выборе столбца, который вызывает медленный возврат. Вы должны попытаться использовать субвыборы в левых соединениях или использовать производную таблицу, как я определил ниже.
Использование левого соединения к двум экземплярам третьей таблицы
Использование производной таблицы
источник
Попробуйте применить кросс вместо
Вы также можете использовать CTE и row_number или встроенный запрос, используя MIN
источник
Переместите биты JOIN из основной части предложения и поместите его как подвыбор. Перемещение его в разделы WHERE и JOIN гарантирует, что вам не придется выбирать TOP 1 снова и снова, что, по-моему, и является причиной медлительности. Если вы хотите проверить это, изучите план выполнения.
источник
В
ThirdTable
ссылки, (суб выбирает в вашем примере), необходимо и тот же индекс внимания , как и любая другая часть запроса.Независимо от того, используете ли вы суб выбирает:
ЛЕВЫЕ СОЕДИНЕНИЯ (как предложил Джон Хартсок):
ПРИМЕНЕНИЕ КРЕСТА (как предложено Конрадом Фриксом):
Вы должны убедиться ,
covering indexes
определены дляThirdTable.SomeColumn
иThirdTable.SomeOtherColumn
и индексы являются уникальными. Это означает, что вам нужно будет дополнительно квалифицироватьThirdTable
ссылки, чтобы исключить выбор нескольких строк и повысить производительность. Выборsub selects
,LEFT JOIN
илиCROSS APPLY
будет на самом деле не имеет значения , пока вы не улучшить селективность в отношенииThirdTable.SomeColumn
иThirdTable.SomeOtherColumn
пути включения большего количества столбцов для обеспечения уникальной селективности. До тех пор, я ожидаю, что ваша производительность будет продолжать страдать.covering index
Тема хорошо представлена Maziar Тахери; не повторяя его работы, я подчеркиваю необходимость принять близко к сердцу использование указателей покрытия.Короче говоря: повышение селективности для
ThirdTable.SomeColumn
иThirdTable.SomeOtherColumn
запросов (или соединение) путем добавления связанных в таблице-столбцы , чтобы обеспечить уникальное совпадение строк. Если это невозможно, то вы будете продолжать страдать от проблем с производительностью, так как двигатель занят вытягиванием рядов, которые впоследствии выбрасываются. Это влияет на ваш ввод / вывод, процессор и, в конечном итоге, на план выполнения.источник