Mendirikan
Saya memiliki tabel besar ~ 115.382.254 baris. Tabel ini relatif sederhana dan mencatat operasi proses aplikasi.
CREATE TABLE [data].[OperationData](
[SourceDeciveID] [bigint] NOT NULL,
[FileSource] [nvarchar](256) NOT NULL,
[Size] [bigint] NULL,
[Begin] [datetime2](7) NULL,
[End] [datetime2](7) NOT NULL,
[Date] AS (isnull(CONVERT([date],[End]),CONVERT([date],'19000101',(112)))) PERSISTED NOT NULL,
[DataSetCount] [bigint] NULL,
[Result] [int] NULL,
[Error] [nvarchar](max) NULL,
[Status] [int] NULL,
CONSTRAINT [PK_OperationData] PRIMARY KEY CLUSTERED
(
[SourceDeviceID] ASC,
[FileSource] ASC,
[End] ASC
))
CREATE TABLE [model].[SourceDevice](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_DataLogger] PRIMARY KEY CLUSTERED
(
[ID] ASC
))
ALTER TABLE [data].[OperationData] WITH CHECK ADD CONSTRAINT [FK_OperationData_SourceDevice] FOREIGN KEY([SourceDeviceID])
REFERENCES [model].[SourceDevice] ([ID])
Tabel ini berkerumun di sekitar 500 cluster dan setiap hari.
Selain itu, tabel diindeks dengan baik oleh PK, statistik terkini dan INDEXer dirusak setiap malam.
SELECT berbasis indeks cepat kilat dan kami tidak punya masalah dengan itu.
Masalah
Saya perlu tahu baris terakhir (TOP) [End]
dan dipartisi oleh [SourceDeciveID]
. Untuk mendapatkan yang terakhir [OperationData]
dari setiap perangkat sumber.
Pertanyaan
Saya perlu menemukan cara untuk menyelesaikan ini dengan cara yang baik dan tanpa membawa DB ke batas.
Upaya 1
Percobaan pertama jelas GROUP BY
atau SELECT OVER PARTITION BY
permintaan. Masalahnya di sini juga jelas, setiap query harus memindai urutan partisi yang sangat / menemukan baris atas. Jadi permintaannya sangat lambat dan memiliki dampak IO yang sangat tinggi.
Contoh permintaan 1
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY [SourceDeciveID] ORDER BY [End] DESC) AS rn
FROM [data].[OperationData]
)
SELECT *
FROM cte
WHERE rn = 1
Contoh permintaan 2
SELECT *
FROM [data].[OperationData] AS d
CROSS APPLY
(
SELECT TOP 1 *
FROM [data].[OperationData]
WHERE [SourceDeciveID] = d.[SourceDeciveID]
ORDER BY [End] DESC
) AS ds
GAGAL!
Usaha 2
Saya membuat tabel bantuan untuk selalu memegang referensi ke baris TOP.
CREATE TABLE [data].[LastOperationData](
[SourceDeciveID] [bigint] NOT NULL,
[FileSource] [nvarchar](256) NOT NULL,
[End] [datetime2](7) NOT NULL,
CONSTRAINT [PK_LastOperationData] PRIMARY KEY CLUSTERED
(
[SourceDeciveID] ASC
)
ALTER TABLE [data].[LastOperationData] WITH CHECK ADD CONSTRAINT [FK_LastOperationData_OperationData] FOREIGN KEY([SourceDeciveID], [FileSource], [End])
REFERENCES [data].[OperationData] ([SourceDeciveID], [FileSource], [End])
Untuk mengisi tabel pemicu yang dibuat untuk selalu menambah / memperbarui baris sumber jika [End]
kolom yang lebih tinggi dimasukkan.
CREATE TRIGGER [data].[OperationData_Last]
ON [data].[OperationData]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
MERGE [data].[LastOperationData] AS [target]
USING (SELECT [SourceDeciveID], [FileSource], [End] FROM inserted) AS [source] ([SourceDeciveID], [FileSource], [End])
ON ([target].[SourceDeciveID] = [FileSource].[SourceDeciveID])
WHEN MATCHED AND [target].[End] < [source].[End] THEN
UPDATE SET [target].[FileSource] = source.[FileSource], [target].[End] = source.[End]
WHEN NOT MATCHED THEN
INSERT ([SourceDeciveID], [FileSource], [End])
VALUES (source.[SourceDeciveID], source.[FileSource], source.[End]);
END
Masalahnya di sini adalah, itu juga memiliki dampak IO yang sangat besar dan saya tidak tahu mengapa.
Seperti yang Anda lihat di sini dalam rencana kueri itu juga menjalankan pemindaian seluruh [OperationData]
tabel.
Ini memiliki dampak keseluruhan yang sangat besar pada DB saya.
GAGAL!
CREATE TABLE
skrip tetapi di dalam rencana kueri Anda akan melihat partisi. Saya akan mengedit pertanyaan.
PRIMARY KEY CLUSTERED
Anda pikir itu dapat membantu?
SELECT [SourceID], [Source], [End] FROM inserted
beberapa cara melakukan pemindaian tabel pada [OperationData]
.