ฉันมีปัญหากับ INSERT จำนวนมากที่บล็อกการดำเนินการ SELECT ของฉัน
schema
ฉันมีโต๊ะแบบนี้:
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]
ขั้นตอนอย่างรวดเร็ว
นอกจากนี้ยังมีเว็บไซต์ที่ใช้แบบสอบถามบน[InverterData]
ตาราง
ปัญหา
ถ้าฉันเลือกแบบสอบถามบน[InverterData]
ตารางพวกเขาจะดำเนินการในช่วงเวลาที่แตกต่างกันขึ้นอยู่กับการใช้ INSERT ของอินสแตนซ์บริการของฉัน ถ้าฉันหยุดอินสแตนซ์การบริการทั้งหมดไว้ชั่วคราว SELECT นั้นเร็วเกินไปถ้าอินสแตนซ์ดำเนินการอย่างรวดเร็วการแทรก SELECT จะช้าลงอย่างมากหรือแม้กระทั่งการหมดเวลายกเลิก
ความพยายามในการ
ฉันเลือก SELECT บางตัวบน[sys.dm_tran_locks]
โต๊ะเพื่อหากระบวนการล็อคเช่นนี้
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 = แชร์แล้ว เซสชันการพักจะได้รับการเข้าถึงทรัพยากรร่วมกัน
คำถาม
ทำไม SELECTs ถูกบล็อกโดย[InsertOrUpdateInverterData]
โพรซีเดอร์ที่ใช้คำสั่ง MERGE เท่านั้น?
ฉันต้องใช้ธุรกรรมบางประเภทกับโหมดแยกที่กำหนดไว้ภายใน[InsertOrUpdateInverterData]
หรือไม่
อัปเดต 1 (เกี่ยวข้องกับคำถามจาก @Paul)
ฐานการรายงานภายในเซิร์ฟเวอร์ MS-SQL เกี่ยวกับ[InsertOrUpdateInverterData]
สถิติต่อไปนี้:
- เวลา CPU เฉลี่ย: 0.12ms
- กระบวนการอ่านเฉลี่ย: 5.76 ต่อ / s
- กระบวนการเขียนเฉลี่ย: 0.4 ต่อ / s
ดูเหมือนว่าคำสั่ง MERGE ส่วนใหญ่จะยุ่งอยู่กับการอ่านที่จะล็อคตาราง! (?)
อัปเดต 2 (เกี่ยวข้องกับคำถามจาก @Paul)
[InverterData]
ตารางต่อไปนี้ได้มีการจัดเก็บข้อมูลสถิติ:
- พื้นที่ข้อมูล: 26,901.86 MB
- จำนวนแถว: 131,827,749
- แบ่งพาร์ติชันแล้ว: จริง
- จำนวนพาร์ติชัน: 62
นี่คือชุดผลลัพธ์sp_WhoIsActive (allmost) ที่สมบูรณ์:
SELECT
คำสั่ง
- dd hh: mm: ss.mss: 00 00: 01: 01.930
- session_id: 73
- wait_info: (12629ms) LCK_M_S
- CPU: 198
- บล็อค_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
- การปิดกั้น_session_id: NULL
- อ่าน: 376,95
- เขียน: 126
- สถานะ: นอนหลับ
- open_tran_count: 1
([TimeStamp] DESC, [InverterID] ASC)
ดูเหมือนจะเป็นทางเลือกที่แปลกสำหรับดัชนีคลัสเตอร์ ฉันหมายถึงDESC
ส่วนหนึ่ง