いくつかのデータを受け取り、値を選択し、いくつかのレコードを挿入してからその値を返す、かなり単純なストアド プロシージャを作成しました。しかし、本番環境では実行に時間がかかりすぎて、最終的には 1 日に数十万回実行する必要があり、30000 回しか実行していない場合でも、他のプロセスに悪影響を及ぼしています。
まず、クエリを調べて、WHERE 句で使用される日付フィールドにインデックスを追加しました。次に、SQL Server Profiler を実行しました。結果を Tuning Advisor に送り、それが思いついたインデックス作成の提案を実装しました。過去に、そのツールが非常に醜いインデックスを呼び出すのを見たことがありますが、今回は意味のある単一の追加が必要だったので、追加しました。これらの各ステップが役に立ちました。しかし、それでも遅すぎます。
ほぼ瞬時の 2 つの挿入ではなく、最初のクエリがホールドアップであることが簡単にわかりました。そのため、サブクエリの実行時間を含めて、当時私が持っていたものは次のとおりです。
--all combined, this typically takes in the range of 1200-1500 ms but occasionally spikes up to ~2200 ms
select coalesce(
(
--when the following is run, this takes ~690 ms
select MIN(maxes.imbsn)
from (
--when the following is run without the higher limiting scopes, this takes ~3600 ms
select imbsn, MAX(assignmentDate) maxAD
from imbsnAssignments
group by imbsn
) maxes
where datediff(d, maxes.maxAD, GETDATE()) > 90
)
,
(
--this is rarely executed but takes ~0 ms when it is
select max(imbsn)+1 from imbsnAssignments
)
)
当時の状況から考えると、合体がうまくいっていないように見えました (これは、実行計画の読み方がわかっていれば、実行計画で検証できると思いますが、まだ実行計画はほとんど残っていません。私の貧弱な脳には不透明です)。合体を取り除くために、クエリを次のように変更しました。
--this runs ~480-700 ms
select MIN(maxes.imbsn)
from (
select imbsn, MAX(assignmentDate) maxAD
from imbsnAssignments
group by imbsn
union
select max(imbsn)+1, getDate()
from imbsnAssignments
) maxes
where datediff(d, maxes.maxAD, GETDATE()) > 90
これは大きな改善です。しかし、それはまだかなり遅いです。
Profiler-Tuning Advisor が私に変更を加えることをまだ望んでいないことを確認してから、ここに来てすべてを尋ねました。これにより、2つのアプローチが残されると思います.1)基本的なアルゴリズムを維持しますが、それからより高い効率を絞り出すか、2)私が知らない方法で同じ基本的な効果を得るためのよりスマートな方法に切り替えますが、1つは明らかです私がここである種のアンチパターンに従事していることを嗅ぎつけているあなたの頭脳の1つに。
お時間とご関心をお寄せいただきありがとうございます。
この追加情報の期待される形式が正確にはわかりませんが、試してみます。表は次のとおりです。
CREATE TABLE [dbo].[imbsnAssignments](
[id] [int] IDENTITY(1,1) NOT NULL,
[imbsn] [int] NOT NULL,
[assignmentDate] [date] NOT NULL,
[jobCode] [varchar](10) NOT NULL,
[name] [varchar](45) NOT NULL,
[a1] [varchar](45) NOT NULL,
[a2] [varchar](45) NOT NULL,
[a3] [varchar](45) NOT NULL,
[a4] [varchar](45) NOT NULL,
[city] [varchar](40) NOT NULL,
[state] [char](10) NOT NULL,
[zip] [varchar](10) NOT NULL,
[batchIdent] [varchar](256) NOT NULL,
CONSTRAINT [PK_imbsnAssignments] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
これはインデックスを表示する「正しい」方法ではないと思いますが、
TableName IndexName IndexType
imbsnAssignments PK_imbsnAssignments CLUSTERED
imbsnAssignments IX_imbsnAssignments_assignmentDate NONCLUSTERED
imbsnAssignments _dta_index_imbsnAssignments_36_149575571__K2_3 NONCLUSTERED
実行計画:
|--Stream Aggregate(DEFINE:([Expr1013]=MIN([partialagg1018])))
|--Concatenation
|--Stream Aggregate(DEFINE:([partialagg1018]=MIN([IMB].[dbo].[imbsnAssignments].[imbsn])))
| |--Filter(WHERE:([Expr1003]<dateadd(day,(-90),getdate())))
| |--Stream Aggregate(GROUP BY:([IMB].[dbo].[imbsnAssignments].[imbsn]) DEFINE:([Expr1003]=MAX([IMB].[dbo].[imbsnAssignments].[assignmentDate])))
| |--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED FORWARD)
|--Stream Aggregate(DEFINE:([partialagg1018]=MIN([Expr1009])))
|--Compute Scalar(DEFINE:([Expr1009]=[Expr1008]+(1)))
|--Stream Aggregate(DEFINE:([Expr1008]=MAX([IMB].[dbo].[imbsnAssignments].[imbsn])))
|--Top(TOP EXPRESSION:((1)))
|--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED BACKWARD)