当前位置 : 主页 > 网络安全 > 测试自动化 >

为什么ISNULL会提高查询的性能?

来源:互联网 收集:自由互联 发布时间:2021-06-22
我们目前正试图加速一些查询,我们遇到了一些我(不是DBA只是.NET开发人员)无法解释或理解的东西.我们在SQL Server 2005上运行此查询. 我们有以下查询(为了参数而做小而简单); SELECT *FROM
我们目前正试图加速一些查询,我们遇到了一些我(不是DBA只是.NET开发人员)无法解释或理解的东西.我们在SQL Server 2005上运行此查询.

我们有以下查询(为了参数而做小而简单);

SELECT    
    *
FROM    
    RandomTable 
WHERE   
    MoneyColumn <> 0
GROUP BY
    SomeColumn

此查询在大约三秒内运行,然后我们随机尝试跟随加速(真的在黑暗中拍摄)

SELECT    
    *
FROM    
    RandomTable 
WHERE   
    isnull(MoneyColumn,0) <> 0
GROUP BY
    SomeColumn

这会将查询速度降低到大约一秒钟.

这个列没有NULL值(但是由于数据库设计很糟糕)但是它是空的……

它是否为NULLABLE,这使得SQL Server可以做些什么来解决这个问题,这使得它在没有提到ISNULL的地方变慢了?我根本不知道为什么ISNULL会让它表现得更快(并且如此大的余地).我认为当查询中有ISNULL语句时,SQL实际上还有更多工作要做.

任何人都可以对此有所了解吗?

EDIT执行计划已添加

有了ISNULL

<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0" Build="9.00.5000.00" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="9019.76" StatementId="1" StatementOptmLevel="FULL" StatementSubTreeCost="1.48105" StatementText="SELECT    debiteur_id, MIN(Faktuurdatum) AS OldestOpenInvoiceDate, ISNULL(SUM(Totaal_Open),0) AS TotalOpenAmount&#xD;&#xA;FROM    dbo.tbl_Faktuur &#xD;&#xA;WHERE   (Afgehandeld_NeeJa = 0 OR Afgehandeld_NeeJa IS NULL)&#xD;&#xA;AND        (ISNULL(Totaal_Open,0) &lt;&gt; 0) &#xD;&#xA;--AND        (Totaal_Open &lt;&gt; 0) &#xD;&#xA;GROUP BY debiteur_id" StatementType="SELECT">
          <StatementSetOptions ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="false" />
          <QueryPlan DegreeOfParallelism="1" MemoryGrant="1520" CachedPlanSize="54" CompileTime="11" CompileCPU="11" CompileMemory="704">
            <RelOp AvgRowSize="23" EstimateCPU="0.000901976" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="9019.76" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="1.48105">
              <OutputList>
                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                <ColumnReference Column="Expr1003" />
                <ColumnReference Column="Expr1005" />
              </OutputList>
              <ComputeScalar>
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Column="Expr1005" />
                    <ScalarOperator ScalarString="isnull([Expr1004],($0.0000))">
                      <Intrinsic FunctionName="isnull">
                        <ScalarOperator>
                          <Identifier>
                            <ColumnReference Column="Expr1004" />
                          </Identifier>
                        </ScalarOperator>
                        <ScalarOperator>
                          <Const ConstValue="($0.0000)" />
                        </ScalarOperator>
                      </Intrinsic>
                    </ScalarOperator>
                  </DefinedValue>
                </DefinedValues>
                <RelOp AvgRowSize="23" EstimateCPU="0.291662" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="9019.76" LogicalOp="Compute Scalar" NodeId="1" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="1.48014">
                  <OutputList>
                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                    <ColumnReference Column="Expr1003" />
                    <ColumnReference Column="Expr1004" />
                  </OutputList>
                  <ComputeScalar>
                    <DefinedValues>
                      <DefinedValue>
                        <ColumnReference Column="Expr1004" />
                        <ScalarOperator ScalarString="CASE WHEN [Expr1013]=(0) THEN NULL ELSE [Expr1014] END">
                          <IF>
                            <Condition>
                              <ScalarOperator>
                                <Compare CompareOp="EQ">
                                  <ScalarOperator>
                                    <Identifier>
                                      <ColumnReference Column="Expr1013" />
                                    </Identifier>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Const ConstValue="(0)" />
                                  </ScalarOperator>
                                </Compare>
                              </ScalarOperator>
                            </Condition>
                            <Then>
                              <ScalarOperator>
                                <Const ConstValue="NULL" />
                              </ScalarOperator>
                            </Then>
                            <Else>
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Column="Expr1014" />
                                </Identifier>
                              </ScalarOperator>
                            </Else>
                          </IF>
                        </ScalarOperator>
                      </DefinedValue>
                    </DefinedValues>
                    <RelOp AvgRowSize="23" EstimateCPU="0.291662" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="9019.76" LogicalOp="Aggregate" NodeId="2" Parallel="false" PhysicalOp="Hash Match" EstimatedTotalSubtreeCost="1.48014">
                      <OutputList>
                        <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                        <ColumnReference Column="Expr1003" />
                        <ColumnReference Column="Expr1013" />
                        <ColumnReference Column="Expr1014" />
                      </OutputList>
                      <MemoryFractions Input="1" Output="1" />
                      <RunTimeInformation>
                        <RunTimeCountersPerThread Thread="0" ActualRows="156794" ActualEndOfScans="1" ActualExecutions="1" />
                      </RunTimeInformation>
                      <Hash>
                        <DefinedValues>
                          <DefinedValue>
                            <ColumnReference Column="Expr1003" />
                            <ScalarOperator ScalarString="MIN([directpay].[dbo].[tbl_Faktuur].[Faktuurdatum])">
                              <Aggregate AggType="MIN" Distinct="false">
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                                  </Identifier>
                                </ScalarOperator>
                              </Aggregate>
                            </ScalarOperator>
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Column="Expr1013" />
                            <ScalarOperator ScalarString="COUNT_BIG([directpay].[dbo].[tbl_Faktuur].[Totaal_Open])">
                              <Aggregate AggType="COUNT_BIG" Distinct="false">
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                                  </Identifier>
                                </ScalarOperator>
                              </Aggregate>
                            </ScalarOperator>
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Column="Expr1014" />
                            <ScalarOperator ScalarString="SUM([directpay].[dbo].[tbl_Faktuur].[Totaal_Open])">
                              <Aggregate AggType="SUM" Distinct="false">
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                                  </Identifier>
                                </ScalarOperator>
                              </Aggregate>
                            </ScalarOperator>
                          </DefinedValue>
                        </DefinedValues>
                        <HashKeysBuild>
                          <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                        </HashKeysBuild>
                        <RelOp AvgRowSize="23" EstimateCPU="0.255" EstimateIO="0.634196" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="27420" LogicalOp="Index Seek" NodeId="4" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.889196">
                          <OutputList>
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                          </OutputList>
                          <RunTimeInformation>
                            <RunTimeCountersPerThread Thread="0" ActualRows="298726" ActualEndOfScans="1" ActualExecutions="1" />
                          </RunTimeInformation>
                          <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" NoExpandHint="false">
                            <DefinedValues>
                              <DefinedValue>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                              </DefinedValue>
                              <DefinedValue>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                              </DefinedValue>
                              <DefinedValue>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                              </DefinedValue>
                            </DefinedValues>
                            <Object Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Index="[_dta_index_tbl_Faktuur_5_583009158__K13_K9_K19_K2_5]" />
                            <SeekPredicates>
                              <SeekPredicate>
                                <Prefix ScanType="EQ">
                                  <RangeColumns>
                                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Afgehandeld_NeeJa" />
                                  </RangeColumns>
                                  <RangeExpressions>
                                    <ScalarOperator ScalarString="(0)">
                                      <Const ConstValue="(0)" />
                                    </ScalarOperator>
                                  </RangeExpressions>
                                </Prefix>
                              </SeekPredicate>
                            </SeekPredicates>
                            <Predicate>
                              <ScalarOperator ScalarString="isnull([directpay].[dbo].[tbl_Faktuur].[Totaal_Open],($0.0000))&lt;($0.0000) OR isnull([directpay].[dbo].[tbl_Faktuur].[Totaal_Open],($0.0000))&gt;($0.0000)">
                                <Logical Operation="OR">
                                  <ScalarOperator>
                                    <Compare CompareOp="LT">
                                      <ScalarOperator>
                                        <Intrinsic FunctionName="isnull">
                                          <ScalarOperator>
                                            <Identifier>
                                              <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                                            </Identifier>
                                          </ScalarOperator>
                                          <ScalarOperator>
                                            <Const ConstValue="($0.0000)" />
                                          </ScalarOperator>
                                        </Intrinsic>
                                      </ScalarOperator>
                                      <ScalarOperator>
                                        <Const ConstValue="($0.0000)" />
                                      </ScalarOperator>
                                    </Compare>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Compare CompareOp="GT">
                                      <ScalarOperator>
                                        <Intrinsic FunctionName="isnull">
                                          <ScalarOperator>
                                            <Identifier>
                                              <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                                            </Identifier>
                                          </ScalarOperator>
                                          <ScalarOperator>
                                            <Const ConstValue="($0.0000)" />
                                          </ScalarOperator>
                                        </Intrinsic>
                                      </ScalarOperator>
                                      <ScalarOperator>
                                        <Const ConstValue="($0.0000)" />
                                      </ScalarOperator>
                                    </Compare>
                                  </ScalarOperator>
                                </Logical>
                              </ScalarOperator>
                            </Predicate>
                          </IndexScan>
                        </RelOp>
                      </Hash>
                    </RelOp>
                  </ComputeScalar>
                </RelOp>
              </ComputeScalar>
            </RelOp>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

没有ISNULL

<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0" Build="9.00.5000.00" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1322.43" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.274954" StatementText="SELECT    debiteur_id, MIN(Faktuurdatum) AS OldestOpenInvoiceDate, ISNULL(SUM(Totaal_Open),0) AS TotalOpenAmount&#xD;&#xA;FROM    dbo.tbl_Faktuur &#xD;&#xA;WHERE   (Afgehandeld_NeeJa = 0 OR Afgehandeld_NeeJa IS NULL)&#xD;&#xA;--AND        (ISNULL(Totaal_Open,0) &lt;&gt; 0) &#xD;&#xA;AND        (Totaal_Open &lt;&gt; 0) &#xD;&#xA;GROUP BY debiteur_id" StatementType="SELECT">
          <StatementSetOptions ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="false" />
          <QueryPlan CachedPlanSize="47" CompileTime="9" CompileCPU="9" CompileMemory="528">
            <RelOp AvgRowSize="23" EstimateCPU="0.000132243" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1322.43" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="0.274954">
              <OutputList>
                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                <ColumnReference Column="Expr1003" />
                <ColumnReference Column="Expr1005" />
              </OutputList>
              <ComputeScalar>
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Column="Expr1005" />
                    <ScalarOperator ScalarString="isnull([Expr1004],($0.0000))">
                      <Intrinsic FunctionName="isnull">
                        <ScalarOperator>
                          <Identifier>
                            <ColumnReference Column="Expr1004" />
                          </Identifier>
                        </ScalarOperator>
                        <ScalarOperator>
                          <Const ConstValue="($0.0000)" />
                        </ScalarOperator>
                      </Intrinsic>
                    </ScalarOperator>
                  </DefinedValue>
                </DefinedValues>
                <RelOp AvgRowSize="23" EstimateCPU="0.167304" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1322.43" LogicalOp="Aggregate" NodeId="1" Parallel="false" PhysicalOp="Hash Match" EstimatedTotalSubtreeCost="0.274822">
                  <OutputList>
                    <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                    <ColumnReference Column="Expr1003" />
                    <ColumnReference Column="Expr1004" />
                  </OutputList>
                  <MemoryFractions Input="0" Output="0" />
                  <Hash>
                    <DefinedValues>
                      <DefinedValue>
                        <ColumnReference Column="Expr1003" />
                        <ScalarOperator ScalarString="MIN([directpay].[dbo].[tbl_Faktuur].[Faktuurdatum])">
                          <Aggregate AggType="MIN" Distinct="false">
                            <ScalarOperator>
                              <Identifier>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                              </Identifier>
                            </ScalarOperator>
                          </Aggregate>
                        </ScalarOperator>
                      </DefinedValue>
                      <DefinedValue>
                        <ColumnReference Column="Expr1004" />
                        <ScalarOperator ScalarString="SUM([directpay].[dbo].[tbl_Faktuur].[Totaal_Open])">
                          <Aggregate AggType="SUM" Distinct="false">
                            <ScalarOperator>
                              <Identifier>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                              </Identifier>
                            </ScalarOperator>
                          </Aggregate>
                        </ScalarOperator>
                      </DefinedValue>
                    </DefinedValues>
                    <HashKeysBuild>
                      <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                    </HashKeysBuild>
                    <RelOp AvgRowSize="23" EstimateCPU="0.030319" EstimateIO="0.0771991" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="27420" LogicalOp="Index Seek" NodeId="2" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.107518">
                      <OutputList>
                        <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                        <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                        <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                      </OutputList>
                      <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" NoExpandHint="false">
                        <DefinedValues>
                          <DefinedValue>
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Debiteur_ID" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Faktuurdatum" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                          </DefinedValue>
                        </DefinedValues>
                        <Object Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Index="[_dta_index_tbl_Faktuur_5_583009158__K13_K9_K19_K2_5]" />
                        <SeekPredicates>
                          <SeekPredicate>
                            <Prefix ScanType="EQ">
                              <RangeColumns>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Afgehandeld_NeeJa" />
                              </RangeColumns>
                              <RangeExpressions>
                                <ScalarOperator ScalarString="(0)">
                                  <Const ConstValue="(0)" />
                                </ScalarOperator>
                              </RangeExpressions>
                            </Prefix>
                            <EndRange ScanType="LT">
                              <RangeColumns>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                              </RangeColumns>
                              <RangeExpressions>
                                <ScalarOperator ScalarString="($0.0000)">
                                  <Const ConstValue="($0.0000)" />
                                </ScalarOperator>
                              </RangeExpressions>
                            </EndRange>
                          </SeekPredicate>
                          <SeekPredicate>
                            <Prefix ScanType="EQ">
                              <RangeColumns>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Afgehandeld_NeeJa" />
                              </RangeColumns>
                              <RangeExpressions>
                                <ScalarOperator ScalarString="(0)">
                                  <Const ConstValue="(0)" />
                                </ScalarOperator>
                              </RangeExpressions>
                            </Prefix>
                            <StartRange ScanType="GT">
                              <RangeColumns>
                                <ColumnReference Database="[directpay]" Schema="[dbo]" Table="[tbl_Faktuur]" Column="Totaal_Open" />
                              </RangeColumns>
                              <RangeExpressions>
                                <ScalarOperator ScalarString="($0.0000)">
                                  <Const ConstValue="($0.0000)" />
                                </ScalarOperator>
                              </RangeExpressions>
                            </StartRange>
                          </SeekPredicate>
                        </SeekPredicates>
                      </IndexScan>
                    </RelOp>
                  </Hash>
                </RelOp>
              </ComputeScalar>
            </RelOp>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>
ISNULL()版本构成了谓词 unsargable的一部分.

除了意味着它不能有效地使用索引(它仍然可以从查询中的另一个谓词中寻找前导列),这也使得构造在估计行数时对优化器更加不透明那将匹配.

两个计划都有大约27,420行进入哈希匹配运算符,但它们的估计行数有多少不同.较快的计划估计为9,019,较慢的计划为1,322.

这两个估计实际上都是非常错误的,因为实际上您的组有156,794个不同的值.由于错误的估计,查询没有分配足够的内存来构建哈希表,并且两者都需要溢出到光盘.较慢的一个特别是内存不足,所以这种情况多次发生.

您可以尝试更新现有统计信息或查看创建一些多列统计信息,以便尝试更准确地估计将返回的不同组的数量,从而分配不同的计划或更多内存.

网友评论