Оптимизация запросов sproc SQL Server - PullRequest
0 голосов
/ 11 февраля 2010

У меня есть приложение, которое генерирует данные для отчетов, которые выглядят так:

                    age < 30   | age >=30  |   asian   | hispanic
-----------------------------------------------------------------
clients in prog A              |          |           |
-----------------------------------------------------------------
clients in prog B              |          |           |
-----------------------------------------------------------------
number clients                 |          |           |
-----------------------------------------------------------------
number children                |          |           |

Запросы иногда очень и очень длинные, и я бы хотел их оптимизировать.

У меня нет прав на сервере для запуска анализатора запросов (и я читал, что часто не лучше использовать его предложения). Самые длинные спроки выполняются за ~ 35 секунд.

Читая, вещи, которых следует избегать при высокой оптимизации запросов:

  • Выбрать *
  • существует
  • 1020 * отчетливый *
  • курсоры
  • имеет

У меня есть несколько вопросов о задаче:

  • на какую разницу я смотрю, меняя Select * на Select colA, colB ...? Это действительно стоит потраченных усилий?
  • как я могу оптимизировать, если существует (...)? Является ли if (Select Count (query)> 0) хорошей оптимизацией?
  • Если я действительно собираюсь вернуть всех столбцов в таблице, можно ли использовать Select *?

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

Ответы [ 5 ]

1 голос
/ 11 февраля 2010

Я пытаюсь по возможности использовать повторно используемые функции и временные таблицы, чтобы облегчить нагрузку как на мой мозг, так и на сервер.

Предполагая, что вы имеете в виду пользовательские функции, они не всегда хороши для производительности. Стремление уменьшить нагрузку на мозг может привести к увеличению нагрузки на сервер. Чисто скалярные (то есть принимающие значение, манипулирующие им и возвращающие другое значение) должны быть в порядке, но те, которые сканируют таблицы, обычно могут работать быстрее, когда их логика используется в хранимой процедуре напрямую. Например, функция, которая сканирует таблицу X на наличие значений Y и возвращает счетчик, будет выполняться медленнее (из-за повторных обращений к ней), чем инструкция SQL, содержащая объединение, которое может выполнить подсчет каждого значения за один раз.

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

1 голос
/ 11 февраля 2010

1) Какую разницу я вижу, изменив Select * на Select colA, colB ...? Это действительно стоит потраченных усилий?
Это может иметь большое значение - обычно рекомендуется всегда указывать нужные поля и только эти поля. то есть, если вы делаете SELECT *, чтобы вернуть 50 полей, когда вам нужно только 2 из них, и эти 2 поля включены в подходящий индекс, тогда все данные могут быть предоставлены из индекса без необходимости искать остальные данные из страницы данных. Так что это намного лучше.

2) как я могу оптимизировать, если существует (...)? Является ли if (Select Count (query)> 0) хорошей оптимизацией?
Нет ... ВЫБРАТЬ СЧЕТ () хуже. EXISTS - это самый эффективный способ сделать это, поскольку он оптимизирован, чтобы прекратить проверку, как только он найдет первую соответствующую запись. Принимая во внимание, что COUNT () будет продолжать работать, пока не найдет их все, что не нужно. Я бы не стал классифицировать «EXISTS» в плохом лагере с курсорами вообще.

3) Если я действительно собираюсь вернуть все столбцы в таблице, можно ли использовать Select *?
Ну, если вы действительно хотите их всех, тогда это не так важно. Это предполагает, что если вы хотите добавить больше столбцов в будущем, вы также хотите, чтобы те также возвращались, что может привести к поломке существующего кода, если он внезапно изменится.

1 голос
/ 11 февраля 2010

Можете ли вы опубликовать запрос

вот только некоторые указатели, потому что вы не показываете код

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

select col1, col2 лучше, чем select *, потому что если столбцы находятся в некластеризованном индексе, то базовая таблица / кластеризованный индекс даже не будут затронуты, это еще более верно теперь, когда вы включили столбцы в индексы. вы также будете использовать меньше полосы пропускания, если будете возвращать только те столбцы, которые вам нужны

Если я действительно собираюсь вернуть все столбцы в таблице, можно ли использовать Select *?

что если позже кто-нибудь добавит 4 столбца в таблицу? Теперь вы будете возвращать эти 4 столбца также

0 голосов
/ 11 февраля 2010

Для подсчета наиболее эффективной формой является SELECT Count (1) FROM table. (Или 0 или 123 или любое простое постоянное значение).

Вам также следует выбрать SELECT field1, field2, ... для удобства управления. SELECT * работает медленнее, и позже вы можете столкнуться с проблемами при изменении кода, представлений или таблиц (или нескольких из них)

0 голосов
/ 11 февраля 2010

Вы не получите большой пользы от перехода с Select * на Select column1, column2, .... Однако вы должны сделать это, потому что это хорошее кодирование. Если в будущем кто-то изменит порядок столбцов или количество столбцов, это может привести к сбою отчетов в зависимости от их построения.

Как насчет другого подхода? Если вы можете добавить некластеризованные индексы в свои таблицы, я бы посоветовал изучить это. В частности, посмотрите на существующие подзапросы и посмотрите, есть ли у столбцов в разделе «Где» индекс. Если этого не произойдет, вы будете выполнять сканирование таблицы каждый раз, когда существующий возвращает false, и вы можете выполнять сканирование таблицы каждый раз, даже если оно возвращает true (это зависит от того, где находится значение). Некластеризованные индексы позволят подзапросам быстро находить любые результаты в вашей таблице. Иногда вам приходится использовать неэффективные запросы, но если вы можете оптимизировать структуру таблиц с помощью индексов, это окажет гораздо меньшее влияние на вашу скорость.

Кроме того, для ваших подзапросов Exists когда-либо будет получен максимум 1 результат? Если это так, то вы можете попробовать сделать левое соединение с таблицей. Это, вероятно, не поможет, если у вас нет индекса для обоих наборов столбцов слева и справа от вашего объединения, но если вы это сделаете, это должно быть довольно полезно, поскольку вы в основном сканировали бы правую таблицу 1 раз, а не один раз в строке .

...