微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么参数化 LIKE 谓词会导致更高的成本?

如何解决为什么参数化 LIKE 谓词会导致更高的成本?

我使用的是 sql Server 2016 企业版,看到了一些关于参数化 LIKE 谓词的奇怪行为。

这里有一些示例代码来演示这个问题。 CUSTLABEL 字段上有一个索引。未参数化的最后一个查询的成本显着降低:

declare @custlabel_wildcard varchar(50) = 'Patient%'
declare @custlabel_no_wildcard varchar(50) = 'Patient'

-- Cost .23
select count(*) from GR_CUST_FIELD_DATA where CUSTLABEL like @custlabel_wildcard
-- Cost .23
select count(*) from GR_CUST_FIELD_DATA where CUSTLABEL like @custlabel_no_wildcard + '%'
-- Cost .067
select count(*) from GR_CUST_FIELD_DATA where CUSTLABEL like 'Patient%'

一个查询的计划在这里https://www.brentozar.com/pastetheplan/?id=BkzUb6OEd

最后一次查询的计划在这里https://www.brentozar.com/pastetheplan/?id=H1r9b6OVu

解决方法

差异只是由于参数化情况下的基数估计不同。

在文字的情况下,它可以在编译时告诉它需要在范围 >'PatienSþ' and < 'PatienU' 上做一个搜索谓词(这些是根据文字和您的排序规则计算的)并产生非常准确的基数估计寻求。

enter image description here

在参数化的情况下,它会将要查找的确切索引范围推迟到运行时。它有一个返回的计算标量

  • [Expr1006] = 标量运算符(LikeRangeStart([@custlabel_wildcard])),
  • [Expr1007] = 标量运算符(LikeRangeEnd([@custlabel_wildcard])),
  • [Expr1008] = 标量运算符(LikeRangeInfo([@custlabel_wildcard]))

Expr1006Expr1007 用于索引查找操作。这种额外的抽象级别意味着它可以回退到对谓词基数的猜测。

enter image description here

现在的查找成本好像需要读取 45,883 行(并且流聚合好像需要处理那么多行)。实际情况是,它仍然读取和返回与第一个计划相同的行数,因此成本过高。

您可能想知道在以通配符开头的参数值传递给 @custlabel 的情况下,上述方法是如何工作的。在这种情况下,动态计算的搜索范围的开始和结束将覆盖可以存储在该列中的非空值的整个域(然后搜索将读取其中 CUSTLABEL IS NOT NULL LIKE 表达式上的残差谓词将保留实际匹配的谓词)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。