少し遅いクエリがあります。
SELECT b.BreakdownClassificationId,
k.IsinCode,
k.SedolCode,
ClassificationDate,
NAME,
InstrumentType,
GeographicalLocation,
CapSize,
Currency,
ExchangeName,
HoldingDomicile,
MaturityDate,
Sector,
MajorSector
FROM #BreakdownSet b
OUTER apply (SELECT TOP 1 IsinCode,
SedolCode,
ClassificationDate,
NAME,
InstrumentType,
GeographicalLocation,
CapSize CapSize,
Currency,
ExchangeName,
HoldingDomicile,
MaturityDate,
Sector,
MajorSector
FROM dbfinex.dbo.PfPortfolioHoldingClassificationFtid x WITH (nolock)
WHERE ( x.isincode > ''
AND x.isincode = b.breakdowncode )
OR ( x.sedolcode > ''
AND x.sedolcode = b.breakdowncode )
OR ( x.sedolcode > ''
AND x.sedolcode = b.sedolcode )
OR ( x.isincode > ''
AND x.isincode = b.isincode )
ORDER BY CASE
WHEN x.sedolcode = b.breakdowncode THEN 1
WHEN x.isincode = b.breakdowncode THEN 2
WHEN x.sedolcode = b.sedolcode THEN 3
WHEN x.isincode = b.isincode THEN 4
ELSE 5
END,
classificationdate DESC) k
実行計画
Order By
内部Cross Apply
は非常にコストがかかります。このクエリを作成するより良い方法はありますか?
必要に応じて並べ替えを削除できますが、クエリのパフォーマンスを向上させる必要があるかどうかはわかりません。重要なのは、ORDER BY
句と検索条件をどのように構築したかです。 x.sedolcode = b.breakdowncode
に一致する行がある場合は、その行を取得します。それ以外の場合は、次の条件に進みます。適切なインデックスを使用すると、APPLY
を分割することでソートを回避できます。 SQL Serverクエリオプティマイザーは、実際にOR
条件をUNION
sに変換するため、Niceヒントを提供します。
私が求めている一般的なクエリプランの形状を示すために、限られた例を作成します。また、PfPortfolioHoldingClassificationFtid
テーブルのPK
列に主キーとクラスタリングキーがあると仮定します。これが私のテストデータです:
CREATE TABLE #BreakdownSet (
BreakdownClassificationId BIGINT NOT NULL,
breakdowncode VARCHAR(10) NULL,
sedolcode VARCHAR(10) NULL,
isincode VARCHAR(10) NULL
);
INSERT INTO #BreakdownSet
SELECT
t.RN
, CASE WHEN RN % 10 = 1 THEN t.RN ELSE NULL END
, CASE WHEN RN % 10 = 4 THEN t.RN ELSE NULL END
, CASE WHEN RN % 10 = 7 THEN t.RN ELSE NULL END
FROM
(
SELECT TOP (1500000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) t;
CREATE TABLE dbo.PfPortfolioHoldingClassificationFtid (
PK BIGINT NOT NULL,
isincode VARCHAR(10) NOT NULL,
sedolcode VARCHAR(10) NOT NULL,
ClassificationDate DATE NOT NULL,
OTHER_COLUMN VARCHAR(200) NOT NULL,
PRIMARY KEY (PK)
);
INSERT INTO dbo.PfPortfolioHoldingClassificationFtid WITH (TABLOCK)
SELECT
t.RN
, t.RN
, t.RN
, DATEADD(DAY, t.rn / 100, '20170101')
, REPLICATE('OTHER', 40)
FROM
(
SELECT TOP (1500000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) t;
CREATE INDEX isin_date ON dbo.PfPortfolioHoldingClassificationFtid (isincode, ClassificationDate);
CREATE INDEX sedol_date ON dbo.PfPortfolioHoldingClassificationFtid (sedolcode, ClassificationDate);
これが私のテーブル定義を使用したクエリです。
SELECT b.breakdownclassificationid,
k.isincode,
k.sedolcode,
classificationdate,
other_column
FROM #breakdownset b
OUTER apply (SELECT TOP 1 isincode,
sedolcode,
classificationdate,
other_column
FROM dbo.pfportfolioholdingclassificationftid x WITH (
nolock)
WHERE ( x.isincode > ''
AND x.isincode = b.breakdowncode )
OR ( x.sedolcode > ''
AND x.sedolcode = b.breakdowncode )
OR ( x.sedolcode > ''
AND x.sedolcode = b.sedolcode )
OR ( x.isincode > ''
AND x.isincode = b.isincode )
ORDER BY CASE
WHEN x.sedolcode = b.breakdowncode THEN 1
WHEN x.isincode = b.breakdowncode THEN 2
WHEN x.sedolcode = b.sedolcode THEN 3
WHEN x.isincode = b.isincode THEN 4
ELSE 5
END,
classificationdate DESC) k;
当然のことながら、私はあなたとは別の計画を立てていますが、その種類にはまだ高い推定コストがあります。 APPLY
を4つの部分に分割し、各APPLY
がテーブルの主キーのみを返すようにするとどうなるでしょうか。各APPLY
にカバーするインデックスがある場合、最大4つのインデックスシークで一致する行の主キーを見つけることができます。並べ替えは必要ありません。 APPLY
sにフィルターを追加することで、不要なシークをスキップすることもできますが、これは保証された動作ではありません。これを記述する1つの方法を次に示します。
SELECT b.breakdownclassificationid,
k.isincode,
k.sedolcode,
classificationdate,
other_column
FROM #breakdownset b
OUTER apply (SELECT TOP 1 pk
FROM dbo.pfportfolioholdingclassificationftid x
WHERE x.sedolcode = b.breakdowncode
ORDER BY classificationdate DESC) a1
OUTER apply (SELECT TOP 1 pk
FROM dbo.pfportfolioholdingclassificationftid x
WHERE x.isincode = b.breakdowncode
AND a1.pk IS NOT NULL
ORDER BY classificationdate DESC) a2
OUTER apply (SELECT TOP 1 pk
FROM dbo.pfportfolioholdingclassificationftid x
WHERE x.sedolcode = b.sedolcode
AND a2.pk IS NOT NULL
ORDER BY classificationdate DESC) a3
OUTER apply (SELECT TOP 1 pk
FROM dbo.pfportfolioholdingclassificationftid x
WHERE x.isincode = b.isincode
AND a3.pk IS NOT NULL
ORDER BY classificationdate DESC) a4
LEFT OUTER JOIN dbo.pfportfolioholdingclassificationftid k
ON k.pk = COALESCE(a1.pk, a2.pk, a3.pk, a4.pk);
一時テーブルに150万行ある場合、最悪のケースは600万の非クラスター化インデックスシークと150万のクラスター化インデックスシークです。
クエリは私のマシンで2秒で実行されます。ナンセンスなデータがあるので、ランタイムは関係ありません。ただし、計画はありません。クエリプランを Paste The Plan にアップロードしました。将来の質問についても同様に検討する必要があります。これも実際の計画のスクリーンショットです。
あなたが持っているクエリは、ネストされたループ結合を行い、並列処理を行いません。 LOOP JOIN
とMAXDOP 1
ヒントを使用すると、クエリは私のマシンで7秒で終了します。こちらが 計画 で、こちらがスクリーンショットです。