SQL Server 查询性能优化——索引与SARG(三)
上接SQL Server 查询性能优化——索引与SARG(二)
2 请不要进行负向查询
除了不应该对字段数据进行计算外,非SARG 语句的格式语句还包含在WHERE条件子句中,使用负向查询操作符。
如NOT 、!=、<> 、!>、!<、NOT EXISTS 、NOT IN及NOT LIKE 等,因为通过有顺序的索引结构,SQL SERVER 可以有效地利用二分法进行查找,快速找到相应的数据,但是如果查询条件是不要什么数据,其余的都要(就是负向查询), 则 无法利用索引进行二分查找,只能进行全表扫描或聚集索引扫描。
以下同样是负向操作健立的SARG 条件查询与非SARG 条件查询范例。从中可以看出两者的执行成本是不一样的,相差十倍左右,但是其数据查询的记录数量也不一样。个人理解查询优化程序是根据数据查询的记录数量,来决定使用哪种执行计划。
逻辑读 |
执行成本 | ||||
SELECT * FROM [WBK_PDE_ LIST_ORG_ HISTROY] where QTY_1=312
|
有主键(索引1,索引2) |
1 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取137 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。 |
137 |
|
|
0.121935 |
||||
无主键(索引2) |
2 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取43 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
43 |
||
|
0.121935 |
||||
SELECT * FROM [WBK_PDE_ LIST_ORG_ HISTROY] where QTY_1<>312
|
有主键(索引1,索引2) |
3 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取1314 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
1314 |
|
|
1.03687 |
||||
无主键(索引2) |
4 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取1306 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
1306 |
||
|
1.03687 |
||||
小结:
查询语句 |
逻辑读 |
查询记录数量 |
执行成本 |
1 |
137 |
37 |
0.121935 |
2 |
43 |
37 |
0.121935 |
3 |
1314 |
60796 |
1.03687 |
4 | 1306 | 60796 | 1.03687 |
3 不要在WHERE子句中对字段使用函数
在查询语句中对字段使用函数,就是对字段数据进行计算,所以这些都不算是SARG。使用函数之后 ,SQL SERVER 需要将数据表内所有记录的相关字段输入到函数中,如果有100万条记录,就需要调用函数100万次,这将是性能杀手。
下面列出两个非SARG与SARG的查询成本区别的示例。
逻辑读 |
||||
SELECT * FROM [WBK_PDE_LIST_ORG_HISTROY] where dbo.f_qty(QTY_1,G_QTY)=400 |
||||
数值函数计算 |
1 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取1428 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
1428 |
|
|
1.03687 |
|||
SELECT * FROM [WBK_PDE_LIST_ORG_HISTROY] where QTY_1=200 and G_QTY=200 |
||||
2 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取428 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
428 |
||
|
0.42645 |
|||
SELECT * FROM [WBK_PDE_LIST_ORG_HISTROY] where dbo.[f_ByteLeft](wbook_no,14)='BE404942450013' |
||||
字符函数计算 |
3 |
表'Worktable'。扫描计数0,逻辑读取0 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。 表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数2,逻辑读取850 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。 |
850 |
|
|
1.03904 |
|||
SELECT * FROM [WBK_PDE_LIST_ORG_HISTROY] where wbook_no='BE404942450013' |
||||
4 |
表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取3 次,物理读取0 次,预读0 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
|
3 |
||
|
0.0033071 |
|||
小结:
查询语句 |
逻辑读 |
查询记录数量 |
执行成本 |
1 |
1428 |
3873 |
1.03687 |
2 |
136 |
37 |
0.42645 |
3 |
850 |
3873 |
1.03904 |
4 | 3 | 22 | 0.0033071 |
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器