web-dev-qa-db-ja.com

非常に類似した多くの開始値を持つVARCHAR列にインデックスがあると、パフォーマンスが低下しますか

インデックスを使用するクエリで、非常に異常なパフォーマンス低下が発生しているようです。たとえば、テーブルは次のようになります

  • PK BIGINT
  • ID VARCHAR(50)
  • 列1
  • 列2

したがって、データベースに行を挿入し、後でそれをIDで検索する必要があります。ただし、サードパーティのIDとPKがあります。 PKを取り戻す必要があります。しかし、これらのIDの非常に広い範囲は、非常に類似した開始値を持っています。例えば

  • 「// 45-423484834893457」
  • "// 45-573459834589345"
  • "// 45-345345345345345

SQL Serverが値をハッシュしたり、左端の位置から文字列比較を行ったりする場合、SQL ServerがBTreeをどのようにトラバースするかわかりません。

非常に広い範囲の非常に類似した値(少なくとも最初の4文字は同一)があると、それらの値を照会するときにインデックスのパフォーマンスが低下する可能性がありますか?

更新:

検索クエリは申し訳ありません

SELECT PK_Column FROM table WHERE ID = @ID

マークリクエスト:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 22 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 30 ms.

(1 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

(1 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.0.4000.0" xmlns="http://schemas.Microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="TRIVIAL" StatementSubTreeCost="0.0032831" StatementText="SELECT&#xD;&#xA;      LocalMsgId&#xD;&#xA;    FROM&#xD;&#xA;      Pdu (nolock)&#xD;&#xA;  WHERE&#xD;&#xA;     RemoteMsgId = '41/00/2789aeb8/1127796335811'&#xD;&#xA;      &#xD;" StatementType="SELECT" ParameterizedText="(@1 varchar(8000))SELECT [LocalMsgId] FROM [Pdu](nolock) WHERE [RemoteMsgId]=@1" QueryHash="0x677C78E75E33C4C7" QueryPlanHash="0xB358D862A43E4853">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan CachedPlanSize="16" CompileTime="7406" CompileCPU="1970" CompileMemory="120">
            <RelOp AvgRowSize="23" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Index Seek" NodeId="0" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0032831" TableCardinality="5074270">
              <OutputList>
                <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="LocalMsgId" />
              </OutputList>
              <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="LocalMsgId" />
                  </DefinedValue>
                </DefinedValues>
                <Object Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Index="[IX_Pdu_RemoteMsgId]" IndexKind="NonClustered" />
                <SeekPredicates>
                  <SeekPredicateNew>
                    <SeekKeys>
                      <Prefix ScanType="EQ">
                        <RangeColumns>
                          <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="RemoteMsgId" />
                        </RangeColumns>
                        <RangeExpressions>
                          <ScalarOperator ScalarString="[@1]">
                            <Identifier>
                              <ColumnReference Column="@1" />
                            </Identifier>
                          </ScalarOperator>
                        </RangeExpressions>
                      </Prefix>
                    </SeekKeys>
                  </SeekPredicateNew>
                </SeekPredicates>
              </IndexScan>
            </RelOp>
            <ParameterList>
              <ColumnReference Column="@1" ParameterCompiledValue="'41/00/2789aeb8/1127796335811'" />
            </ParameterList>
          </QueryPlan>
        </StmtSimple>
      </Statements>
      <Statements>
        <StmtSimple StatementCompId="2" StatementId="2" StatementText="&#xA;SET STATISTICS IO OFF&#xD;&#xA;" StatementType="SET STATS" />
      </Statements>
    </Batch>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementId="1" StatementText="SET STATISTICS TIME OFF&#xD;&#xA;" StatementType="SET STATS" />
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>
6
uriDium

使用しているクエリによって異なります。 MS SQL Serverは常にバランスのとれたBTreeインデックスを使用しますが、次のようなクエリを使用する場合:

select * from table where field like 'some%'

ほとんどのレコードがこの条件に対応しているため、MS SQL Serverは、インデックススキャンやインデックスルックアップの代わりにテーブルスキャンを使用する方が安くなると判断できます。

追加:とにかく 計算列 を使用してフィールド値を逆にし、 インデックスを作成する =。

2
demas

実行計画から、その1つのクエリに対して実行できることは実際には多くありません。それはすでに最適です。

私の本当の質問は次のとおりです。何がisパフォーマンスの問題ですか?

単一のステートメントでも遅い場合、システムがビジー状態で、インデックスページがキャッシュから落ちていますか?最大メモリ設定は正しく構成されていますか?このような広いインデックスフィールドを使用しても、メモリ内のインデックスページのトラバースは比較的高速です。

プロファイラーを見ていて、これらの小さなクエリがたくさん表示されている場合、ループ内で単一の行SELECTsを実行するある種のバッチプロセスについて話していますか?これはアプリケーションの問題です。セットベースの操作の代わりにシングルトンルックアップを実行すると、どのシステムでも問題が発生する可能性があります。

2
Jon Seigel

通常はありませんが、すぐに断片化する傾向があります。この post を見て、インデックスが実際に断片化されているかどうかを確認してください。その場合、それを修正する方法についても説明します。

0
Mike Perrenoud