使用或条件+;join中的函数似乎混淆了SQL Server';s查询优化器
我正在努力调试特定查询的性能。问题是:使用或条件+;join中的函数似乎混淆了SQL Server';s查询优化器,sql,sql-server,Sql,Sql Server,我正在努力调试特定查询的性能。问题是: 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 O
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)
)
该查询在一个不同的名字表(包含大约15k行)上运行一个Jaro Winkler过滤器,然后将其与用户表进行内部连接以生成结果集。根据定义,运行用户表中约500k行大约需要1分钟
以下是我所知道的:
1) Jaro Winkler过滤器几乎是即时的(自身为0.1s)
2) 如果我将user子句更改为仅包含一列(即删除ORs),则只需0.4s
3) 如果我将此更改为三个查询,并背靠背运行它们,大约需要2秒
4) 如果我将Jaro Winkler过滤器更改为0.99(因此只有一个结果),则查询执行时间没有实质性差异
5) 如果我用相等操作(dfn.first_name='john')替换Jaro Winkler过滤器,则总查询时间将减少到4s
(所有计时都相当缓慢;现实生活中的表现会更好。)
因此,出于某种原因,函数和ORs的组合使查询优化器感到困惑。执行计划信息量不大;它说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">
将查询拆分实际上是一种选择,因为这是一个存储过程,我可能会重新设计一点模式,但我很难说是什么让它陷入困境。有什么想法吗?一些你可能想尝试的事情:
- dfn表的聚集索引是什么?这只是一张有名字的桌子吗?如果是,请删除“自动编号”列(如果有的话),并将该名称作为聚集索引
- “约翰”是你狂欢的理由吗?我想是的。您可以首先在两个名称数据集中最小的数据集上计算Jaro Winkler过滤器,并将其插入到临时表中。然后连接临时表上的另一个表。请记住,临时表也可以从索引中获益(如果您添加索引的话)
- 您可以通过创建多列索引来提高性能:名字、昵称、中间名。由于where语句中引用的所有列,单个索引的有用性会降低
- 我认为运行SQL Tuning advisor工具并查看它提供了什么样的建议总是很有趣的。只需将监视器附加到SQL server实例,并将查询的执行情况记录到工作负载文件中即可。然后,您可以将工作负载文件提供给advisor工具,如果启用该选项,它将建议索引、统计信息甚至模式更改
- 尽可能预先计算。如果我没记错的话,在Jaro Winkler过滤器中,字符串长度是一个重要因素。您可以使用名称的字符串长度向dfn表中添加一列。函数和视图之类的东西很好,但不一定是性能最好的。该函数就像一个黑匣子,无法利用任何预先存在或预先计算的数据
基于文本列的查询总是更难优化。您可能希望查看全文索引以进一步提高性能,但这是一个单独的主题需要研究。您可能希望尝试的一些事情:
- dfn表的聚集索引是什么?这只是一张有名字的桌子吗?如果是,请删除“自动编号”列(如果有的话),并将该名称作为聚集索引
- “约翰”是你狂欢的理由吗?我想是的。您可以首先在两个名称数据集中最小的数据集上计算Jaro Winkler过滤器,并将其插入到临时表中。然后连接临时表上的另一个表。请记住,临时表也可以从索引中获益(如果您添加索引的话)
- 您可以通过创建多列索引来提高性能:名字、昵称、中间名。由于where语句中引用的所有列,单个索引的有用性会降低
- 我认为运行SQL Tuning advisor工具并查看它提供了什么样的建议总是很有趣的。只需将监视器附加到SQL server实例,并将查询的执行情况记录到工作负载文件中即可。然后,您可以将工作负载文件提供给advisor工具,如果启用该选项,它将建议索引、统计信息甚至模式更改
- 尽可能预先计算。如果我没记错的话,在Jaro Winkler过滤器中,字符串长度是一个重要因素。您可以使用名称的字符串长度向dfn表中添加一列。函数和视图之类的东西很好,但不一定是性能最好的。该函数就像一个黑匣子,无法利用任何预先存在或预先计算的数据
基于文本列的查询总是更难优化。您可能希望查看全文索引以进一步提高性能,但这是一个单独的主题需要研究。您可能希望尝试的一些事情:
- dfn表的聚集索引是什么?这只是一张有名字的桌子吗?如果是,请删除“自动编号”列(如果有的话),并将该名称作为聚集索引
- “约翰”是一个论点吗