SELECT işlemlerimi engelleyen büyük miktarda INSERT ile ilgili bir sorunum var.
Şema
Ben böyle bir tablo var:
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)
)
Ayrıca MERGE komutuyla eklemem veya güncellememi (çakışmada güncelleme) sağlayan bu küçük yardımcı yordam var:
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
kullanım
Şimdi [InsertOrUpdateInverterData]
yordamı hızla çağırarak büyük güncelleştirmeleri gerçekleştiren birden çok sunucuda hizmet örnekleri çalıştırdım .
[InverterData]
Tabloda SELECT sorguları yapan bir web sitesi de var .
Sorun
[InverterData]
Tabloda SELECT sorguları yaparsam, bunlar servis örneklerimin INSERT kullanımına bağlı olarak farklı zaman aralıklarında ilerler. Tüm hizmet örneklerini duraklatırsam SELECT yıldırım hızındadır, örnek hızlı ekleme gerçekleştirirse SELECT'ler gerçekten yavaşlar, hatta bir zaman aşımı iptali olur.
Denemeler
[sys.dm_tran_locks]
Bu gibi kilitleme işlemlerini bulmak için bazı SELECT'ler yaptım
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
Sonuç budur:
S = Paylaşıldı. Bekletme oturumuna kaynağa paylaşılan erişim izni verilir.
Soru
SELECT'ler neden [InsertOrUpdateInverterData]
yalnızca MERGE komutlarını kullanan yordam tarafından engelleniyor ?
İçinde tanımlı izolasyon moduyla bir tür işlem kullanmak zorunda [InsertOrUpdateInverterData]
mıyım?
Güncelleme 1 (@Paul'dan gelen soru ile ilgili)
[InsertOrUpdateInverterData]
Aşağıdaki istatistiklerle ilgili MS-SQL sunucusu dahili raporlamasına dayanır:
- Ortalama CPU Zamanı: 0.12ms
- Ortalama Okuma işlemleri: 5,76 / s
- Ortalama Yazma işlemleri: 0,4 / s
Buna dayanarak, MERGE komutu çoğunlukla tabloyu kilitleyecek okuma işlemleriyle meşgul gibi görünüyor! (?)
Güncelleme 2 (@Paul'dan gelen soru ile ilgili)
Aşağıdaki [InverterData]
tablo istatistiklerine sahiptir:
- Veri alanı: 26.901.86 MB
- Sıra sayısı: 131,827,749
- Bölümlenmiş: true
- Bölüm sayısı: 62
İşte (allmost) tam sp_WhoIsActive sonuç kümesi:
SELECT
komuta
- gg ss: dd: ss.mss: 00 00: 01: 01.930
- oturum_kimliği: 73
- wait_info: (12629ms) LCK_M_S
- İşlemci: 198
- blocking_session_id: 146
- okur: 99.368
- yazar: 0
- durum: askıya alındı
- open_tran_count: 0
Engelleme [InsertOrUpdateInverterData]
komutu
- gg ss: dd: ss.mss: 00 00: 00: 00.330
- oturum_kimliği: 146
- wait_info: NULL
- İşlemci: 3.972
- blocking_session_id: NULL
- okur: 376,95
- yazar: 126
- durumu: uyku
- open_tran_count: 1
([TimeStamp] DESC, [InverterID] ASC)
Bakışlar kümelenmiş dizin için garip bir seçim gibi.DESC
Kısım demek istiyorum .