Что выполнение запроса делает с этим запросом в SQL Server 2005? - PullRequest
0 голосов
/ 22 июня 2010

Сегодня я нашел этот запрос в нашем коде, который выводит список ошибок из нашей базы данных:

SELECT *
FROM   (
        SELECT Substring(title, 9, Patindex('%)%', title) - 9) AS SERVICE, *
        FROM   core.LOG
        WHERE  logtypeid = 1
               AND title LIKE 'Error: (%'
               AND lastmodified > '2010-06-21T00:00:00'
               AND lastmodified < '2010-06-22T00:00:00'
        ) serviceerrors
WHERE SERVICE = 'CheckHelpDeskEmail'  

Сбой из-за следующей ошибки:

Недопустимый параметр длины, переданный в Функция ПОДПИСЬ.

Если я уберу предложение WHERE в самой последней строке, оно будет работать нормально. В качестве альтернативы, если я возьму предложение WHERE из внутреннего подзапроса и переместлю его в основной запрос, оно будет работать нормально. Так что это работает:

SELECT *
FROM   (
        SELECT Substring(title, 9, Patindex('%)%', title) - 9) AS SERVICE, *
        FROM   core.LOG
        ) serviceerrors
WHERE  logtypeid = 1
AND title LIKE 'Error: (%'
AND lastmodified > '2010-06-21T00:00:00'
AND lastmodified < '2010-06-22T00:00:00'
AND SERVICE = 'CheckHelpDeskEmail' 

Кто-нибудь знает почему? Я думаю, что проблема заключается в том, что SQL на самом деле делает несколько прогонов через таблицу core.LOG, и в первый раз он просто запускает строку подстроки во всей таблице, что приводит к сбою, поскольку в некоторых строках не будет знака «)». Однако, если он запускает оставшиеся строки в предложении WHERE, он не найдет ни одной строки, пропущенной ')'. Затем он снова запускает таблицу core.LOG и запускает на ней остальные фильтры. Это кажется неэффективным, поскольку в конечном итоге функция Substring будет выполняться на миллионах строк по сравнению с 15 строками из оставшихся фильтров в предложении WHERE.

Вот мой план выполнения XML

    <?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.3310.00" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="FULL" StatementSubTreeCost="36.4574" StatementText="SELECT *&#xD;&#xA;FROM   (&#xD;&#xA;       SELECT Substring(title, 9, Patindex('%)%', title) - 9) AS SERVICE,&#xD;&#xA;               *&#xD;&#xA;        FROM   core.LOG&#xD;&#xA;        WHERE  logtypeid = 1&#xD;&#xA;               AND title LIKE 'Error: (%'&#xD;&#xA;               AND lastmodified &gt; '2010-06-21T00:00:00'&#xD;&#xA;               AND lastmodified &lt; '2010-06-22T00:00:00'&#xD;&#xA;        ) serviceerrors&#xD;&#xA;WHERE SERVICE = 'CheckHelpDeskEmail'  &#xD;&#xA;" 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="10" CompileCPU="7" CompileMemory="544">
            <RelOp AvgRowSize="4544" EstimateCPU="1E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="36.4574">
              <OutputList>
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                <ColumnReference Column="Expr1003" />
              </OutputList>
              <ComputeScalar>
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Column="Expr1003" />
                    <ScalarOperator ScalarString="substring([Aqueduct].[Core].[Log].[Title],(9),patindex(N'%)%',[Aqueduct].[Core].[Log].[Title])-(9))">
                      <Intrinsic FunctionName="substring">
                        <ScalarOperator>
                          <Identifier>
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                          </Identifier>
                        </ScalarOperator>
                        <ScalarOperator>
                          <Const ConstValue="(9)" />
                        </ScalarOperator>
                        <ScalarOperator>
                          <Arithmetic Operation="SUB">
                            <ScalarOperator>
                              <Intrinsic FunctionName="patindex">
                                <ScalarOperator>
                                  <Const ConstValue="N'%)%'" />
                                </ScalarOperator>
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                  </Identifier>
                                </ScalarOperator>
                              </Intrinsic>
                            </ScalarOperator>
                            <ScalarOperator>
                              <Const ConstValue="(9)" />
                            </ScalarOperator>
                          </Arithmetic>
                        </ScalarOperator>
                      </Intrinsic>
                    </ScalarOperator>
                  </DefinedValue>
                </DefinedValues>
                <RelOp AvgRowSize="4342" EstimateCPU="0.0288036" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Gather Streams" NodeId="1" Parallel="true" PhysicalOp="Parallelism" EstimatedTotalSubtreeCost="36.4574">
                  <OutputList>
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                  </OutputList>
                  <Parallelism>
                    <RelOp AvgRowSize="4342" EstimateCPU="0.0128582" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Filter" NodeId="2" Parallel="true" PhysicalOp="Filter" EstimatedTotalSubtreeCost="36.4286">
                      <OutputList>
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                      </OutputList>
                      <Filter StartupExpression="false">
                        <RelOp AvgRowSize="4342" EstimateCPU="0.0235734" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="11279.1" LogicalOp="Inner Join" NodeId="3" Parallel="true" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="36.4157">
                          <OutputList>
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                          </OutputList>
                          <NestedLoops Optimized="true" WithUnorderedPrefetch="true">
                            <OuterReferences>
                              <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                              <ColumnReference Column="Expr1004" />
                            </OuterReferences>
                            <RelOp AvgRowSize="19" EstimateCPU="0.00628203" EstimateIO="0.0186806" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="11279.1" LogicalOp="Index Seek" NodeId="6" Parallel="true" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0249626">
                              <OutputList>
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                              </OutputList>
                              <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" NoExpandHint="false">
                                <DefinedValues>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                                  </DefinedValue>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                                  </DefinedValue>
                                </DefinedValues>
                                <Object Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Index="[IX_LastModified]" />
                                <SeekPredicates>
                                  <SeekPredicate>
                                    <StartRange ScanType="GT">
                                      <RangeColumns>
                                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                                      </RangeColumns>
                                      <RangeExpressions>
                                        <ScalarOperator ScalarString="'2010-06-21 00:00:00.000'">
                                          <Const ConstValue="'2010-06-21 00:00:00.000'" />
                                        </ScalarOperator>
                                      </RangeExpressions>
                                    </StartRange>
                                    <EndRange ScanType="LT">
                                      <RangeColumns>
                                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModified" />
                                      </RangeColumns>
                                      <RangeExpressions>
                                        <ScalarOperator ScalarString="'2010-06-22 00:00:00.000'">
                                          <Const ConstValue="'2010-06-22 00:00:00.000'" />
                                        </ScalarOperator>
                                      </RangeExpressions>
                                    </EndRange>
                                  </SeekPredicate>
                                </SeekPredicates>
                              </IndexScan>
                            </RelOp>
                            <RelOp AvgRowSize="4447" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="11278.1" EstimateRewinds="0" EstimateRows="1" LogicalOp="Clustered Index Seek" NodeId="8" Parallel="true" PhysicalOp="Clustered Index Seek" EstimatedTotalSubtreeCost="36.3672">
                              <OutputList>
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                                <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                              </OutputList>
                              <IndexScan Lookup="true" Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" NoExpandHint="false">
                                <DefinedValues>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                  </DefinedValue>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Details" />
                                  </DefinedValue>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="IdentifierHash" />
                                  </DefinedValue>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LastModifier" />
                                  </DefinedValue>
                                  <DefinedValue>
                                    <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                                  </DefinedValue>
                                </DefinedValues>
                                <Object Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Index="[PK_Core_Log]" TableReferenceId="-1" />
                                <SeekPredicates>
                                  <SeekPredicate>
                                    <Prefix ScanType="EQ">
                                      <RangeColumns>
                                        <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                                      </RangeColumns>
                                      <RangeExpressions>
                                        <ScalarOperator ScalarString="[Aqueduct].[Core].[Log].[LogId]">
                                          <Identifier>
                                            <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogId" />
                                          </Identifier>
                                        </ScalarOperator>
                                      </RangeExpressions>
                                    </Prefix>
                                  </SeekPredicate>
                                </SeekPredicates>
                              </IndexScan>
                            </RelOp>
                          </NestedLoops>
                        </RelOp>
                        <Predicate>
                          <ScalarOperator ScalarString="substring([Aqueduct].[Core].[Log].[Title],(9),patindex(N'%)%',[Aqueduct].[Core].[Log].[Title])-(9))=N'CheckHelpDeskEmail' AND [Aqueduct].[Core].[Log].[Title] like N'Error: (%' AND [Aqueduct].[Core].[Log].[LogTypeId]=(1)">
                            <Logical Operation="AND">
                              <ScalarOperator>
                                <Compare CompareOp="EQ">
                                  <ScalarOperator>
                                    <Intrinsic FunctionName="substring">
                                      <ScalarOperator>
                                        <Identifier>
                                          <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                        </Identifier>
                                      </ScalarOperator>
                                      <ScalarOperator>
                                        <Const ConstValue="(9)" />
                                      </ScalarOperator>
                                      <ScalarOperator>
                                        <Arithmetic Operation="SUB">
                                          <ScalarOperator>
                                            <Intrinsic FunctionName="patindex">
                                              <ScalarOperator>
                                                <Const ConstValue="N'%)%'" />
                                              </ScalarOperator>
                                              <ScalarOperator>
                                                <Identifier>
                                                  <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                                </Identifier>
                                              </ScalarOperator>
                                            </Intrinsic>
                                          </ScalarOperator>
                                          <ScalarOperator>
                                            <Const ConstValue="(9)" />
                                          </ScalarOperator>
                                        </Arithmetic>
                                      </ScalarOperator>
                                    </Intrinsic>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Const ConstValue="N'CheckHelpDeskEmail'" />
                                  </ScalarOperator>
                                </Compare>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Intrinsic FunctionName="like">
                                  <ScalarOperator>
                                    <Identifier>
                                      <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="Title" />
                                    </Identifier>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Const ConstValue="N'Error: (%'" />
                                  </ScalarOperator>
                                </Intrinsic>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Compare CompareOp="EQ">
                                  <ScalarOperator>
                                    <Identifier>
                                      <ColumnReference Database="[Aqueduct]" Schema="[Core]" Table="[Log]" Column="LogTypeId" />
                                    </Identifier>
                                  </ScalarOperator>
                                  <ScalarOperator>
                                    <Const ConstValue="(1)" />
                                  </ScalarOperator>
                                </Compare>
                              </ScalarOperator>
                            </Logical>
                          </ScalarOperator>
                        </Predicate>
                      </Filter>
                    </RelOp>
                  </Parallelism>
                </RelOp>
              </ComputeScalar>
            </RelOp>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

1 Ответ

4 голосов
/ 22 июня 2010

Ваш код делает неверные предположения. В декларативно-ориентированном множественном языке, таком как SQL, выполнение может свободно выбирать любой план выполнения, который он считает подходящим. То, что вы считаете неэффективным, скорее всего, является действительной оптимизацией, когда заголовок проецируется сначала из индекса, который удовлетворяет предикатам lastmodified или что-то подобное. Вы не можете делать никаких предположений относительно порядка выполнения, и поэтому вам не разрешено иметь в списке проекций выражения типа SUBSTRING (.., 9, ..), которые будут бомбардировать определенные строки.

Другим примером проблем, возникающих из-за недопустимого предположения, являются Короткое замыкание логического оператора SQL Server Ошибки оценки.

...