План выполнения запроса SQL Server показывает неправильное "фактическое количество строк” в используемом индексе, а производительность ужасно низкая

StackOverflow https://stackoverflow.com/questions/225309

Вопрос

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

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

alt text

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

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

Я уже выполнил dbcc dbreindex и ОБНОВИЛ СТАТИСТИКУ без какого-либо успеха.dbcc show_statistics также показывает хорошие данные для индекса.

Процедура создается С ПОМОЩЬЮ ПЕРЕКОМПИЛЯЦИИ, поэтому при каждом ее запуске компилируется новый план выполнения.

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

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, потому что мне это кажется ошибкой.

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

Вы уже пробовали явную СТАТИСТИКА ОБНОВЛЕНИЯ для затронутых таблиц?

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top