Я изо всех сил пытаюсь отладить производительность по конкретному запросу. Запрос таков:
select count(*)
FROM dbo.user d
INNER JOIN dbo.distinct_first_name dfn ON (
[dbo].jw(dfn.first_name, 'john') > 0.8
AND
(d.first_name = dfn.first_name
OR d.nick_name = dfn.first_name
OR d.middle_name = dfn.first_name)
)
Запрос запускает фильтр Джаро Винклера для отдельной таблицы имен (содержащей примерно 15 тыс. строк), а затем выполняет внутреннее соединение с пользовательской таблицей для получения набора результатов. Как определено, это занимает около 1 минуты при примерно 500 тыс. строк в пользовательской таблице.
Вот что я знаю:
1) Фильтр Яро Винклера почти мгновенный (сам по себе 0,1 с)
2) Если я изменю предложение пользователя, чтобы включить только один из столбцов (т.е. удалить ИЛИ), это займет всего 0,4 с.
3) Если я изменю это на три запроса и запущу их подряд, это займет около 2 секунд.
4) Если я изменю фильтр Яро Винклера на 0,99 (чтобы был только один результат), это не будет иметь существенного значения во времени выполнения запроса.
5) Если я заменю фильтр Jaro Winkler операцией равенства (dfn.first_name = 'john'), общее время запроса сократится до 4 с.
(Все тайминги довольно медленные, производительность в реальной жизни будет лучше.)
Итак, по какой-то причине комбинация функции и OR сбивает с толку оптимизатор запросов. План выполнения не очень информативен; в нем говорится, что 90% запроса тратится на:
<RelOp NodeId="63" PhysicalOp="Clustered Index Seek" LogicalOp="Clustered Index Seek" EstimateRows="1.69029" EstimateIO="0.003125" EstimateCPU="0.000158859" AvgRowSize="17" EstimatedTotalSubtreeCost="71.4311" TableCardinality="15958" Parallel="0" EstimateRebinds="448881" EstimateRewinds="0.504024" EstimatedExecutionMode="Row">
<OutputList>
<ColumnReference Database="[mydb]" Schema="[dbo]" Table="[distinct_first_name]" Alias="[dfn]" Column="first_name" />
</OutputList>
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="857936" ActualEndOfScans="859454" ActualExecutions="859454" />
</RunTimeInformation>
<IndexScan Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" ForceScan="0" NoExpandHint="0" Storage="RowStore">
Разделение запроса на самом деле является вариантом, так как это находится в sproc, и я, вероятно, могу немного изменить схему, но я не понимаю, что увязает в этом. Есть идеи?
user
, а затем присоединяется к таблицеdistinct_first_name
. 22.04.2014