Alexander Petrov Asked:2020-01-21 06:34:01 +0000 UTC2020-01-21 06:34:01 +0000 UTC 2020-01-21 06:34:01 +0000 UTC 字符串比较能比数字比较快吗? 772 我读了这篇文章,对提示 #9 感到困惑:Cast for fast search。 他们写道,这个请求: SELECT * FROM HumanResources.EmployeeSick WHERE CAST(SickLeaveHours AS char(3)) <> 0 可以比没有强制转换的请求更快地处理。不总是,但也许。SickLeaveHours有类型int。 怎么会这样?毕竟,常识表明选角需要时间。 sql 2 个回答 Voted Denis Rubashkin 2020-01-23T17:24:50Z2020-01-23T17:24:50Z 这是禁止在 SickLeaveHours 字段上使用索引。假设有一些索引: CREATE INDEX idx_EmployeeSick_SickLeaveHours ON [HumanResources].[EmployeeSick] ( SickLeaveHours ASC ) 然后优化器可以选择以下查询计划: 索引扫描 idx_EmployeeSick_SickLeaveHours(因操作不搜索<>) 对从聚集索引/表接收到的记录进行 KeyLookups,因为我们有一个 SELECT *. 如果为第一项返回足够的记录,则第二次操作在读取方面将非常昂贵,但优化器可能会由于多种原因(例如过时或抽样统计信息)而在估计记录数时出错,并且选择一个带有查找的计划,而不是扫描一个聚集索引/表。 CAST(SickLeaveHours AS char(3)) <> 0当由于列转换而使用谓词时SickLeaveHours,实际上会有两个——显式 tochar(3)和隐式 to ,无法使用int字段索引,因此将使用聚集索引扫描和这样的谓词构建计划:SickLeaveHours CONVERT_IMPLICIT(int,CONVERT(char(3), HumanResources.EmployeeSick.[SickLeaveHours],0),0)<>(0) 正如评论中正确指出的那样,可以通过提示实现相同的结果,明确指定要使用的索引。 Best Answer Герман Борисов 2020-01-21T14:32:42Z2020-01-21T14:32:42Z 怎么会这样? 由于使用索引的特殊性,我可以假设这个技巧可以工作。如果查询必须处理表中一半以上的记录,则全枚举比索引读取更有效。 Firebord 通过加零达到同样的效果:WHERE SickLeaveHours+0 <> 0 铸造需要时间。 与从磁盘读取所需的时间相比,这种强制转换的时间非常短。 通过不必读取索引(除了数据)来减少 I/O 将覆盖强制转换的成本。
这是禁止在 SickLeaveHours 字段上使用索引。假设有一些索引:
然后优化器可以选择以下查询计划:
<>)SELECT *.如果为第一项返回足够的记录,则第二次操作在读取方面将非常昂贵,但优化器可能会由于多种原因(例如过时或抽样统计信息)而在估计记录数时出错,并且选择一个带有查找的计划,而不是扫描一个聚集索引/表。
CAST(SickLeaveHours AS char(3)) <> 0当由于列转换而使用谓词时SickLeaveHours,实际上会有两个——显式 tochar(3)和隐式 to ,无法使用int字段索引,因此将使用聚集索引扫描和这样的谓词构建计划:SickLeaveHours正如评论中正确指出的那样,可以通过提示实现相同的结果,明确指定要使用的索引。
由于使用索引的特殊性,我可以假设这个技巧可以工作。如果查询必须处理表中一半以上的记录,则全枚举比索引读取更有效。
Firebord 通过加零达到同样的效果:
WHERE SickLeaveHours+0 <> 0与从磁盘读取所需的时间相比,这种强制转换的时间非常短。
通过不必读取索引(除了数据)来减少 I/O 将覆盖强制转换的成本。