План выполнения запросов SQL Server показывает неверный «фактический счетчик строк» ​​в используемом индексе, а производительность ужасно низкая - PullRequest
4 голосов
/ 22 октября 2008

Сегодня я наткнулся на интересную проблему с производительностью хранимой процедуры на Sql Server 2005 с пакетом обновления 2 (SP2) в БД, работающей на совместимом уровне 80 (SQL2000).

Процедура выполняется около 8 минут, и план выполнения показывает использование индекса с фактическим количеством строк 1.339.241.423, что примерно в 1000 раз больше, чем "реальный" фактический счетчик строк самой таблицы, который составляет 1.144.640. как показано правильно по приблизительному количеству строк. Таким образом, фактическое количество строк, заданное оптимизатором плана запросов, определенно неверно!

alt text

Интересно, что когда я копирую значения параметров procs внутри proc в локальные переменные и затем использую локальные переменные в реальном запросе, все работает нормально - proc выполняется 18 секунд, и план выполнения показывает правильное действительное количество строк.

РЕДАКТИРОВАТЬ: Как предполагает TrickyNixon, это, кажется, признак проблемы перехвата параметров. Но на самом деле я получаю в обоих случаях один и тот же план выполнения. Одни и те же индексы используются в том же порядке. Единственное различие, которое я вижу, - это путь к большому фактическому количеству строк в индексе PK_ED_Transitions при непосредственном использовании значений параметров.

Я уже выполнил dbcc dbreindex и UPDATE STATISTICS без какого-либо успеха. dbcc show_statistics также показывает хорошие данные для индекса.

Процедура создается с RECOMPILE, поэтому при каждом запуске новый план выполнения компилируется.

Чтобы быть более конкретным - этот работает быстро:

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

declare @local datetime
set @local = @Param

select 
some columns
from 
table1
where
column = @local
group by
some other columns

И эта версия работает очень медленно, но выдает точно такой же план выполнения (кроме слишком большого фактического числа строк в используемом индексе):

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

select 
some columns
from 
table1
where
column = @Param
group by
some other columns

Есть идеи? Кто-нибудь знает, откуда Sql Server получает фактическое значение числа строк при расчете планов запросов?

Обновление : Я пытался выполнить запрос на другом сервере, для которого установлен режим copat 90 (Sql2005). Это то же самое поведение. Я думаю, что открою службу поддержки MS, потому что это выглядит для меня как ошибка.

Ответы [ 5 ]

5 голосов
/ 23 октября 2008

Хорошо, наконец-то я дошел до этого сам.

Два плана запроса отличаются мелкими деталями, которые я сначала пропустил. медленный использует оператор вложенных циклов для объединения двух подзапросов. И это приводит к большому числу при текущем количестве строк в операторе сканирования индекса, что является просто результатом умножения количества строк ввода a на количество строк ввода b.

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

2 голосов
/ 22 октября 2008

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

1 голос
/ 22 октября 2008

Звучит как случай нюхания параметров. Вот отличное объяснение вместе с возможными решениями: Я чую параметр!

Вот еще один поток StackOverflow, который обращается к нему: Отслеживание параметров (или спуфинг) в SQL Server

0 голосов
/ 22 октября 2008

Запускали ли вы sp_spaceused , чтобы проверить, есть ли у SQL Server правильная сводка для этой таблицы? Я полагаю, что в SQL 2000 ядро ​​использовало метаданные такого рода при создании планов выполнения. Раньше нам приходилось запускать DBCC UPDATEUSAGE еженедельно для обновления метаданных некоторых быстро меняющихся таблиц, поскольку SQL Server выбирал неправильные индексы из-за неверных данных о количестве строк.

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

0 голосов
/ 22 октября 2008

Для меня это все еще звучит так, как будто статистика неверна. Перестройка индексов не обязательно обновляет их.

Вы уже пробовали явное UPDATE STATISTICS для затронутых таблиц?

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