sql-server – IF EXISTS比嵌入式select语句花费更长时间
当我运行以下代码时,它需要22.5分钟,并完成1.06亿次读取.但是,如果我只运行内部select语句,它只需要15秒,并且读取264k.作为旁注,select查询不返回任何记录.
任何想法为什么IF EXISTS会让它运行得更长并且读取更多?我还将select语句改为SELECT TOP 1 [dlc].[id],我在2分钟后杀了它. 作为临时修复,我将其更改为count(*)并将该值赋给变量@cnt.然后它做IF 0<>. @cnt声明.但我认为EXISTS会更好,因为如果在select语句中返回了记录,它会在找到至少一条记录后停止执行扫描/搜索,而count(*)将完成整个查询.我错过了什么? IF EXISTS (SELECT [dlc].[ID] FROM TableDLC [dlc] JOIN TableD [d] ON [d].[ID] = [dlc].[ID] JOIN TableC [c] ON [c].[ID] = [d].[ID2] WHERE [c].[Name] <> [dlc].[Name]) BEGIN <do something> END 解决方法
正如我在回答这个相关问题时解释的那样: How (and why) does TOP impact an execution plan? 使用EXISTS引入了一个行目标,优化器生成一个旨在快速定位第一行的执行计划.在此过程中,它假定数据是均匀分布的.例如,如果统计信息显示100,000行中有100个预期匹配项,则假设它必须只读取1,000行才能找到第一个匹配项. 如果这个假设结果有问题,这将导致执行时间超过预期.例如,如果SQL Server选择在搜索中很晚就找到第一个匹配值的访问方法(例如无序扫描),则可能导致几乎完全扫描.另一方面,如果在前几行中发现匹配的行,则性能将非常好.这是行目标的基本风险 – 性能不一致.
通常可以重新构造查询,以便不分配行目标.如果没有行目标,查询仍然可以在遇到第一个匹配行时终止(如果写得正确),但执行计划策略可能会有所不同(希望更有效).显然,count(*)将需要读取所有行,因此它不是一个完美的替代方案. 如果您运行的是SQL Server 2008 R2或更高版本,则通常也可以使用documented and supported trace flag 4138来获取没有行目标的执行计划.也可以使用supported hint OPTION(QUERYTRACEON 4138)指定此标志,但要注意它需要运行时sysadmin权限,除非与计划指南一起使用. 不幸 以上都不适用于IF EXISTS条件语句.它仅适用于常规DML.它将与您尝试的备用SELECT TOP(1)配方一起使用.这可能比使用COUNT(*)更好,后者必须计算所有限定行,如前所述. 也就是说,有许多方法可以表达此要求,这将允许您避免或控制行目标,同时尽早终止搜索.最后一个例子: DECLARE @Exists bit; SELECT @Exists = CASE WHEN EXISTS ( SELECT [dlc].[ID] FROM TableDLC [dlc] JOIN TableD [d] ON [d].[ID] = [dlc].[ID] JOIN TableC [c] ON [c].[ID] = [d].[ID2] WHERE [c].[Name] <> [dlc].[Name] ) THEN CONVERT(bit,1) ELSE CONVERT(bit,0) END OPTION (QUERYTRACEON 4138); IF @Exists = 1 BEGIN ... END; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- SQLServer Job 邮件发送
- sql-server – Sql Server的ISNULL()函数是否是懒惰/短路的
- SqlServer中的对象依赖关系处理
- SqlServer存储过程性能效率的优化方法
- sql-server – 如何使用ASP Classic加密和解密SQL Server数
- sqlserver dateadd
- sql-server – R:使用RODBC和SQL Server来缓慢读取性能
- sql-server – 什么是评估合理缓冲池大小的确定性方法?
- sql-server – SQL Server索引(避免在连接上进行聚簇索引扫
- sql-server-2005 – Sql Server数据透视表不分组结果集