1

SQL Serverでクエリを作成しようとしていますが、約3,000万行(TGS_INFO)のテーブルでテーブルスキャンを実行しているため、クエリの実行が非常に遅くなります。

実際のクエリはもっと​​複雑ですが、同じ問題が発生する単純なバージョンに減らしました。

SELECT DISTINCT UNIT_ITEMS.DBKEY,
    UNIT_ITEMS.ID,
    UNIT_ITEMS.LOCATION1,
    UNIT_ITEMS.LOCATION2
FROM UNIT_ITEMS
INNER JOIN TGS.dbo.TGS_INFO
ON UNIT_ITEMS.UNIT_ID = TGS_INFO.UNIT_ID AND
    UNIT_ITEMS.ITEM_ID = TGS_INFO.ITEM_ID AND
    UNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND
    UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2

これが実行計画です。

StmtText
  |--Sort(DISTINCT ORDER BY:([DbName].[dbo].[UNIT_ITEMS].[DBKEY] ASC, [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION1] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION2] ASC))
       |--Hash Match(Inner Join, HASH:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID], [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID], [DbName].[dbo].[UNIT_ITEMS].[LOCATION1], [DbName].[dbo].[UNIT_ITEMS].[LOCATION2])=([Expr1008], [Expr1009], [Expr1010], [Expr1011]), RESIDUAL:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID]=[Expr1008] AND [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID]=[Expr1009] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION1]=[Expr1010] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION2]=[Expr1011]))
            |--Table Scan(OBJECT:([DbName].[dbo].[UNIT_ITEMS]))
            |--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))
                 |--Table Scan(OBJECT:([TGS].[dbo].[TGS_INFO]))

TGS_INFOとUNIT_ITEMSはどちらも、UNIT_IDとITEM_IDに非クラスター化インデックスを持っています。前述のように、TGS_INFOには約3,000万行がありますが、それらは約1,000の異なるUNIT_IDに均等に分散されています。UNIT_ITEMSには、常に1つのUNIT_IDのみが含まれます。

インデックスは次のとおりです。

CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[TGS_INFO] 
(
    [UNIT_ID] ASC,
    [ITEM_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[UNIT_ITEMS] 
(
    [UNIT_ID] ASC,
    [ITEM_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

コメントで述べたように、TGS_INFOのすべての列はVARCHAR(50)です。UNIT_ITEMSのすべての列はintです。

ちなみに、TGS_INFOのスキーマは設計していません。

4

2 に答える 2

3

インデックスを含めない場合LOCATION1LOCATION2インデックスだけで結合を満足させることはできません。これらの列を両方のテーブルのインデックスに追加します。

おそらく、クエリで参照されている他のすべての列も含める必要があります。

于 2013-01-14T19:29:22.210 に答える
0

実行プランに次のように表示されていることに気付きました。

|--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))

2つのテーブル間のデータ型が結合に使用している列で一致しない場合を除いて、クエリエンジンがこれらの列で暗黙的なデータ型変換を行う正当な理由は考えられません。

インデックスでカバーされていないためUNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2、句に移動してみることもできます。WHEREクエリエンジンは通常、これを説明するのに十分賢いですが、試してみる必要があります。

于 2013-01-14T20:03:00.857 に答える