SQLServer 执行计划的简单学习和与类型转换的影响
  HL7exJhKg9j2 2023年12月12日 29 0

SQLServer 执行计划的简单学习和与类型转换的影响


背景

最近一直在看SQLServer数据库
索引.存储.还有profiler的使用 并且用到了 deadlock graph
但是感觉还是不太深入
数据库的查询计划学习的还是太少. 
正好同事说到了jdbc里面的 :sendStringParametersAsUnicode 
参数的问题.  
一直没搞明白影响程度, 所以想继续学习验证一下.

方式

-- 开启记录的事项
SET STATISTICS TIME ON
SET STATISTICS IO ON
SET STATISTICS PROFILE ON
-- 刷新缓存, 避免有影响. 
dbcc dropcleanbuffers

验证思路

本次主要是想验证 where 条件后面 等于的字符串 在带不带 N 的影响. 

所以执行的SQL主要如下:
SET STATISTICS TIME ON
SET STATISTICS IO ON
SET STATISTICS PROFILE ON

dbcc dropcleanbuffers
--- 第一个SQL
select id from xxx.tablename where id='b45db192-1392-4afd-954b-cb0b5c63abb0'
--- 第二个SQL 
select id from xxx.tablename where id = N'b45db192-1392-4afd-954b-cb0b5c63abb0'

带 N 的执行时间

SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 0 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

(1 行受影响)
表 'TMJSDATA'。扫描计数 1,逻辑读取 4 次,物理读取 4 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(5 行受影响)

(1 行受影响)

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 89 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 0 毫秒。

不带N的执行情况

SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 0 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

(1 行受影响)
表 'TMJSDATA'。扫描计数 0,逻辑读取 4 次,物理读取 4 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(2 行受影响)

(1 行受影响)

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 1 毫秒。
SQL Server 分析和编译时间: 
   CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

 SQL Server 执行时间:
   CPU 时间不是在纤程模式下测量的,占用时间 = 0 毫秒。

分析-基础知识

预读:用于估计信息,去硬盘读取数据到缓存。
物理读:查询计划生成以后,如果发现缓存缺少所需要的数据,让缓存再次去读硬盘数据。
逻辑读:SQLSERVER去内存里的缓存取数据或者执行计划

SQLSERVER存储的最小单位是页,每一页大小为8K,即8*1024=8192字节,
SQLSERVER对页的读取是原子性的,即要么读完一页,要么完全不读。
即使仅仅要获得一条数据,也要读完该页,而页之间的数据组织结构为B树结构。所以SQLSERVER对于逻辑读,物理读,预读的单位是页。

扫描计数是指在SQL查询执行过程中,统计表或索引的扫描次数的过程。
扫描操作常常是影响查询性能的重要因素,因为扫描比索引查找更消耗资源。
官方文档里面的解释为: 
扫描计数是在任何方向都达到叶级别后启动的查询/扫描数,目的在于检索用于构造输出的最终数据集的所有值。

在任意方向到达叶级别之后开始的搜索或扫描次数,搜索/扫描目的是检索所有用于构造输出的最终数据集的值。
如果使用的索引是主键上的唯一索引或聚集索引,且只搜索一个值,则扫描计数为 0。 例如,WHERE Primary_Key_Column = <value>。
当使用对非主键列定义的非唯一的聚集索引搜索一个值时,扫描计数为 1。 此过程的目的是针对你正在搜索的键值检查重复值。 例如,WHERE Clustered_Index_Key_Column = <value>。
当 N 为通过使用索引键定位键值后,在叶级别的左侧或右侧启动的不同查找或扫描数时,则扫描计数为 N

分析-简单结论

因为数据库表结构是 varchar 类型的 where条件强行指定 N之后
发现查询计划出现了偏差. 

会多一次扫描计数, 并且执行的时间也会变长, 的确存在较严重的性能下降. 
查询计划也复杂一些. 所以感觉类型转换在数据库的执行过程中还是存在较严重的性能风险
非常不建议使用. 

建议还是固定好数据结构数据类型. 避免出现字段变更导致性能问题.

带-N 的查询结果

SQLServer 执行计划的简单学习和与类型转换的影响_Server


不带-N的执行计划

SQLServer 执行计划的简单学习和与类型转换的影响_Server_02



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月12日 0

暂无评论

推荐阅读
  biE3E3UjTjeg   2024年01月22日   27   0   0 SQLSQL
HL7exJhKg9j2