Saya memiliki tabel data SQL dengan struktur berikut:
CREATE TABLE Data(
Id uniqueidentifier NOT NULL,
Date datetime NOT NULL,
Value decimal(20, 10) NULL,
RV timestamp NOT NULL,
CONSTRAINT PK_Data PRIMARY KEY CLUSTERED (Id, Date)
)
Jumlah Id yang berbeda berkisar dari 3000 hingga 50.000
. Ukuran tabel bervariasi hingga lebih dari satu miliar baris.
Satu Id dapat mencakup antara beberapa baris hingga 5% dari tabel.
Permintaan tunggal yang paling dieksekusi pada tabel ini adalah:
SELECT Id, Date, Value, RV
FROM Data
WHERE Id = @Id
AND Date Between @StartDate AND @StopDate
Saya sekarang harus menerapkan pengambilan data tambahan pada subset Id, termasuk pembaruan.
Saya kemudian menggunakan skema permintaan di mana pemanggil menyediakan konversi baris tertentu, mengambil blok data dan menggunakan nilai konversi baris maksimum dari data yang dikembalikan untuk panggilan berikutnya.
Saya telah menulis prosedur ini:
CREATE TYPE guid_list_tbltype AS TABLE (Id uniqueidentifier not null primary key)
CREATE PROCEDURE GetData
@Ids guid_list_tbltype READONLY,
@Cursor rowversion,
@MaxRows int
AS
BEGIN
SELECT A.*
FROM (
SELECT
Data.Id,
Date,
Value,
RV,
ROW_NUMBER() OVER (ORDER BY RV) AS RN
FROM Data
inner join (SELECT Id FROM @Ids) Ids ON Ids.Id = Data.Id
WHERE RV > @Cursor
) A
WHERE RN <= @MaxRows
END
Di mana @MaxRows
akan berkisar antara 500.000 dan 2.000.000 tergantung pada seberapa banyak klien akan menginginkan datanya.
Saya telah mencoba berbagai pendekatan:
- Pengindeksan pada (Id, RV):
CREATE NONCLUSTERED INDEX IDX_IDRV ON Data(Id, RV) INCLUDE(Date, Value);
Menggunakan indeks, kueri mencari baris tempat RV = @Cursor
masing-masing Id
masuk @Ids
, baca baris berikut lalu gabungkan hasilnya dan urutkan.
Efisiensi kemudian tergantung pada posisi @Cursor
nilai relatif .
Jika dekat dengan akhir data (dipesan oleh RV) kueri bersifat instan dan jika tidak kueri dapat memakan waktu hingga menit (jangan pernah biarkan berjalan sampai akhir).
masalah dengan pendekatan ini adalah yang @Cursor
mendekati akhir data dan pengurutannya tidak menyakitkan (bahkan tidak diperlukan jika kueri mengembalikan lebih sedikit baris daripada @MaxRows
) baik itu jauh di belakang dan kueri harus mengurutkan @MaxRows * LEN(@Ids)
baris.
- Pengindeksan di RV:
CREATE NONCLUSTERED INDEX IDX_RV ON Data(RV) INCLUDE(Id, Date, Value);
Menggunakan indeks, kueri mencari baris di mana RV = @Cursor
kemudian membaca setiap baris membuang ID yang tidak diminta sampai mencapai @MaxRows
.
Efisiensi kemudian tergantung pada% Id yang diminta ( LEN(@Ids) / COUNT(DISTINCT Id)
) dan distribusinya.
Lebih banyak Id yang diminta% berarti lebih sedikit baris terbuang yang berarti pembacaan lebih efisien, lebih sedikit Id% yang diminta berarti lebih banyak baris yang dibuang yang berarti lebih banyak dibaca untuk jumlah baris yang sama dihasilkan.
Masalah dengan pendekatan ini adalah bahwa jika Id yang diminta hanya berisi beberapa elemen, mungkin harus membaca seluruh indeks untuk mendapatkan baris yang diinginkan.
- Menggunakan indeks yang difilter atau tampilan yang diindeks
CREATE NONCLUSTERED INDEX IDX_RVClient1 ON Data(Id, RV) INCLUDE(Date, Value)
WHERE Id IN (/* list of Ids for specific client*/);
Atau
CREATE VIEW vDataClient1 WITH SCHEMABINDING
AS
SELECT
Id,
Date,
Value,
RV
FROM dbo.Data
WHERE Id IN (/* list of Ids for specific client*/)
CREATE UNIQUE CLUSTERED INDEX IDX_IDRV ON vDataClient1(Id, Rv);
Metode ini memungkinkan pengindeksan sempurna dan rencana eksekusi permintaan tetapi datang dengan kerugian: 1. Secara praktis, saya harus menerapkan SQL dinamis untuk membuat indeks atau tampilan dan memodifikasi prosedur meminta untuk menggunakan indeks atau tampilan yang tepat. 2. Saya harus mempertahankan satu indeks atau tampilan oleh klien yang ada, termasuk penyimpanan. 3. Setiap kali klien harus mengubah daftar Id yang diminta, saya harus menghapus indeks atau melihat dan membuatnya kembali.
Sepertinya saya tidak dapat menemukan metode yang sesuai dengan kebutuhan saya.
Saya mencari ide yang lebih baik untuk mengimplementasikan pengambilan data tambahan. Ide-ide itu bisa menyiratkan pengerjaan ulang skema permintaan atau skema basis data meskipun saya lebih suka pendekatan pengindeksan yang lebih baik jika ada.
Value
kolom. @crokusek: Tidak akan memesan dengan RV, ID bukannya RV hanya menambah beban kerja tanpa bantuan, saya tidak mengerti alasan di balik komentar Anda. Dari apa yang saya baca, RV harus unik kecuali memasukkan data secara khusus ke dalam kolom itu, yang aplikasi tidak.