SELECT操作をブロックしている大量のINSERTに問題があります。
スキーマ
このようなテーブルがあります:
CREATE TABLE [InverterData](
[InverterID] [bigint] NOT NULL,
[TimeStamp] [datetime] NOT NULL,
[ValueA] [decimal](18, 2) NULL,
[ValueB] [decimal](18, 2) NULL
CONSTRAINT [PrimaryKey_e149e28f-5754-4229-be01-65fafeebce16] PRIMARY KEY CLUSTERED
(
[TimeStamp] DESC,
[InverterID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON)
)
また、MERGEコマンドを使用して挿入または更新(競合の更新)を行うことができるこの小さなヘルパープロシージャもあります。
CREATE PROCEDURE [InsertOrUpdateInverterData]
@InverterID bigint, @TimeStamp datetime
, @ValueA decimal(18,2), @ValueB decimal(18,2)
AS
BEGIN
MERGE [InverterData] AS TARGET
USING (VALUES (@InverterID, @TimeStamp, @ValueA, @ValueB))
AS SOURCE ([InverterID], [TimeStamp], [ValueA], [ValueB])
ON TARGET.[InverterID] = @InverterID AND TARGET.[TimeStamp] = @TimeStamp
WHEN MATCHED THEN
UPDATE
SET [ValueA] = SOURCE.[ValueA], [ValueB] = SOURCE.[ValueB]
WHEN NOT MATCHED THEN
INSERT ([InverterID], [TimeStamp], [ValueA], [ValueB])
VALUES (SOURCE.[InverterID], SOURCE.[TimeStamp], SOURCE.[ValueA], SOURCE.[ValueB]);
END
使用法
私は今、複数のサーバー上でサービスインスタンスを実行しました。 [InsertOrUpdateInverterData]
プロシージャをすばやくしました。
SELECTクエリを行うWebサイトもあります [InverterData]
テーブルでます。
問題
SELECTクエリを [InverterData]
テーブルでと、サービスインスタンスのINSERTの使用状況に応じて、異なるタイムスパンで処理されます。すべてのサービスインスタンスを一時停止すると、SELECTは非常に高速になり、インスタンスが高速挿入を実行すると、SELECTが非常に遅くなるか、タイムアウトがキャンセルされます。
試み
[sys.dm_tran_locks]
このようなロックプロセスを見つけるために、テーブルでいくつかのSELECTを実行しました
SELECT
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
これが結果です:
S =共有。保留セッションには、リソースへの共有アクセスが許可されます。
質問
SELECTがブロックされるのはなぜですか [InsertOrUpdateInverterData]
MERGEコマンドのみを使用プロシージャですか?
内部で定義された分離モードで何らかのトランザクションを使用する必要がありますか [InsertOrUpdateInverterData]
ますか?
更新1(@Paulからの質問に関連)
[InsertOrUpdateInverterData]
次の統計に関するMS-SQLサーバーの内部レポートに基づきます。
- 平均CPU時間:0.12ミリ秒
- 平均読み取りプロセス:5.76 per / s
- 平均書き込みプロセス:0.4 per / s
これに基づいて、MERGEコマンドは、テーブルをロックする読み取り操作でほとんど忙しいようです!(?)
更新2(@Paulからの質問に関連)
[InverterData]
次の表には、次のストレージ統計があります。
- データ容量:26,901.86 MB
- 行数:131,827,749
- パーティション分割:true
- パーティション数:62
(ほとんど)完全なsp_WhoIsActive結果セットは次のとおりです。
SELECT
コマンド
- dd hh:mm:ss.mss:00 00:01:01.930
- session_id:73
- wait_info:(12629ms)LCK_M_S
- CPU:198
- blocking_session_id:146
- 読み取り:99,368
- 書き込み:0
- ステータス:一時停止
- open_tran_count:0
ブロック[InsertOrUpdateInverterData]
コマンド
- dd hh:mm:ss.mss:00 00:00:00.330
- session_id:146
- wait_info:NULL
- CPU:3,972
- blocking_session_id:NULL
- 読み取り:376,95
- 書き込み:126
- ステータス:睡眠中
- open_tran_count:1
([TimeStamp] DESC, [InverterID] ASC)
クラスタ化インデックスのための奇妙な選択のように見えます。私はDESC
一部を意味します。