sql-server – 你能解释一下这个执行计划吗?
当我遇到这件事时,我正在研究别的东西.我正在生成包含一些数据的测试表,并运行不同的查询以了解编写查询的不同方式如何影响执行计划.这是我用来生成随机测试数据的脚本:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('t') AND type in (N'U')) DROP TABLE t GO CREATE TABLE t ( c1 int IDENTITY(1,1) NOT NULL,c2 int NULL ) GO insert into t select top 1000000 a from (select t1.number*2048 + t2.number a,newid() b from [master]..spt_values t1 cross join [master]..spt_values t2 where t1.[type] = 'P' and t2.[type] = 'P') a order by b GO update t set c2 = null where c2 < 2048 * 2048 / 10 GO CREATE CLUSTERED INDEX pk ON [t] (c1) GO CREATE NONCLUSTERED INDEX i ON t (c2) GO 现在,根据这些数据,我调用了以下查询: select * from t where c2 < 1048576 or c2 is null ; 令我惊讶的是,为此查询生成的执行计划是this.(对不起外部链接,它太大了,不适合这里). 有人可以向我解释所有这些“Constant Scans”和“Compute Scalars”的内容吗?发生了什么? |--Nested Loops(Inner Join,OUTER REFERENCES:([Expr1010],[Expr1011],[Expr1012])) |--Merge Interval | |--Sort(TOP 2,ORDER BY:([Expr1013] DESC,[Expr1014] ASC,[Expr1010] ASC,[Expr1015] DESC)) | |--Compute Scalar(DEFINE:([Expr1013]=((4)&[Expr1012]) = (4) AND NULL = [Expr1010],[Expr1014]=(4)&[Expr1012],[Expr1015]=(16)&[Expr1012])) | |--Concatenation | |--Compute Scalar(DEFINE:([Expr1005]=NULL,[Expr1006]=NULL,[Expr1004]=(60))) | | |--Constant Scan | |--Compute Scalar(DEFINE:([Expr1008]=NULL,[Expr1009]=(1048576),[Expr1007]=(10))) | |--Constant Scan |--Index Seek(OBJECT:([t].[i]),SEEK:([t].[c2] > [Expr1010] AND [t].[c2] < [Expr1011]) ORDERED FORWARD) 解决方法常量扫描每个都会生成一个没有列的内存行.顶部计算标量输出一行有3列Expr1005 Expr1006 Expr1004 ----------- ----------- ----------- NULL NULL 60 底部计算标量输出一行有3列 Expr1008 Expr1009 Expr1007 ----------- ----------- ----------- NULL 1048576 10 连接运算符将这两行联合在一起并输出3列,但现在它们已重命名 Expr1010 Expr1011 Expr1012 ----------- ----------- ----------- NULL NULL 60 NULL 1048576 10 Expr1012列是一组标志used internally to define certain seek properties for the Storage Engine. 输出2行的下一个计算标量 Expr1010 Expr1011 Expr1012 Expr1013 Expr1014 Expr1015 ----------- ----------- ----------- ----------- ----------- ----------- NULL NULL 60 True 4 16 NULL 1048576 10 False 0 0 最后三列定义如下,在呈现给合并间隔运算符之前仅用于排序目的 [Expr1013] = Scalar Operator(((4)&[Expr1012]) = (4) AND NULL = [Expr1010]),[Expr1014] = Scalar Operator((4)&[Expr1012]),[Expr1015] = Scalar Operator((16)&[Expr1012]) Expr1014和Expr1015只是测试标志中的某些位是否打开. 通过在查询中尝试其他比较运算符,我得到了这些结果 +----------+----------+----------+-------------+----+----+---+---+---+---+ | Operator | Expr1010 | Expr1011 | Flags (Dec) | Flags (Bin) | | | | | | 32 | 16 | 8 | 4 | 2 | 1 | +----------+----------+----------+-------------+----+----+---+---+---+---+ | > | 1048576 | NULL | 6 | 0 | 0 | 0 | 1 | 1 | 0 | | >= | 1048576 | NULL | 22 | 0 | 1 | 0 | 1 | 1 | 0 | | <= | NULL | 1048576 | 42 | 1 | 0 | 1 | 0 | 1 | 0 | | < | NULL | 1048576 | 10 | 0 | 0 | 1 | 0 | 1 | 0 | | = | 1048576 | 1048576 | 62 | 1 | 1 | 1 | 1 | 1 | 0 | | IS NULL | NULL | NULL | 60 | 1 | 1 | 1 | 1 | 0 | 0 | +----------+----------+----------+-------------+----+----+---+---+---+---+ 从中我推断Bit 4的意思是“具有范围的开始”(而不是无界),而第16位意味着范围的起点是包容性的. 这个6列结果集是从SORT运算符中排出的 根据我先前的假设,这种净效应是按以下顺序将范围呈现给合并间隔 ORDER BY HasStartOfRangeAndItIsNullFirst,HasUnboundedStartOfRangeFirst,StartOfRange,StartOfRangeIsInclusiveFirst 合并间隔运算符输出2行 Expr1010 Expr1011 Expr1012 ----------- ----------- ----------- NULL NULL 60 NULL 1048576 10 对于发射的每一行,执行范围搜索 Seek Keys[1]: Start:[dbo].[t].c2 > Scalar Operator([Expr1010]),End: [dbo].[t].c2 < Scalar Operator([Expr1011]) 所以看起来似乎有两次搜寻.一个显然> NULL AND< NULL和一个> NULL AND<然而,传入的标志似乎将其修改为IS NULL和< 1048576.分别为1048576.希望@sqlkiwi可以澄清这一点并纠正任何不准确之处! 如果您稍微更改查询 select * from t where c2 > 1048576 or c2 = 0 ; 然后,使用具有多个搜索谓词的索引搜索,该计划看起来更简单. 该计划显示了Seek Keys Start: c2 >= 0,End: c2 <= 0,Start: c2 > 1048576 SQLKiwi在对earlier linked blog post的评论中给出了为什么这个更简单的计划不能用于OP案例的解释. 具有多个谓词的索引查找不能混合不同类型的比较谓词(即,在OP中的情况下为Is和Eq).这只是产品的当前限制(并且可能是为什么使用> =和< =而不是仅仅为查询获得的直接相等性来实现上一个查询c2 = 0中的相等性测试的原因c2 = 0或c2 = 1048576. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- SQL中的“on ..”和“on .. where”之间的区别加入?
- sqlserver中如何查询出连续日期记录的代码
- 关于sqlserver、access、mysql数据库性能的一个简单测试
- sqlserver中通过osql/ocmd批处理批量执行sql文件的方法
- sqlserver存储过程语法详解
- sql-server-2005 – 无法恢复数据库,数据库正在被会话使用
- 关于Sqlserver2008,修改数据表无法保存的问题
- sql-server-2008 – 使用命名参数调用内联TVF,正确的语法是
- SQLServer2008根据年月时间归总数据
- MySQL 4.1/5.0/5.1/5.5/5.6各版本的主要区别整理