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!
sumber
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]
.Jawaban:
Jika Anda memiliki tabel
SourceID
nilai, dan indeks di tabel utama Anda aktif(SourceID, End) include (othercolumns)
, gunakan sajaOUTER APPLY
.Jika Anda tahu Anda hanya setelah partisi terbaru Anda, Anda bisa memasukkan filter di Akhir, seperti
AND d.[End] > DATEADD(day, -1, GETDATE())
Sunting: Karena indeks kluster Anda aktif
SourceID, Source, End)
, masukkan juga Source ke dalam tabel Sumber Anda dan gabung juga. Maka Anda tidak perlu indeks baru.sumber
Source
Tabel yang merujuksourceID
kolom. Sumber kolom hanya nama file. Itu penamaan yang sedikit membingungkan. Untuk setiapSource
perangkat (sourceID) mungkin hanya ada satu entri tunggal untuk satu filesource
(kolom) pada satu stempel waktu. Juga saya tidak bisa melakukan penghapusan partisi karena yang terbaruEnd
adalah fragmen widly. Itulah mengapa saya datang dengan solusi pemicu. Saya pikir permintaan langsung tidak akan berfungsi di sini.