Dalam pertanyaan Anda, Anda merinci beberapa tes yang telah disiapkan di tempat Anda "membuktikan" bahwa opsi tambahan lebih cepat daripada membandingkan kolom diskrit. Saya menduga metodologi pengujian Anda mungkin cacat dalam beberapa cara, seperti @gbn dan @srutzky menyinggung.
Pertama, Anda perlu memastikan Anda tidak menguji SQL Server Management Studio (atau klien apa pun yang Anda gunakan). Misalnya, jika Anda menjalankan SELECT *
dari tabel dengan 3 juta baris, Anda sebagian besar menguji kemampuan SSMS untuk menarik baris dari SQL Server dan membuat mereka di layar. Anda jauh lebih baik menggunakan sesuatu SELECT COUNT(1)
yang meniadakan kebutuhan untuk menarik jutaan baris di jaringan, dan menampilkannya di layar.
Kedua, Anda harus mengetahui cache data SQL Server. Biasanya, kami menguji kecepatan membaca data dari penyimpanan, dan memproses data itu, dari cold-cache (yaitu buffer SQL Server kosong). Kadang-kadang, masuk akal untuk melakukan semua pengujian Anda dengan cache hangat, tetapi Anda perlu mendekati pengujian Anda secara eksplisit dengan mempertimbangkan hal itu.
Untuk tes cold-cache, Anda harus menjalankan CHECKPOINT
dan DBCC DROPCLEANBUFFERS
sebelum menjalankan setiap tes.
Untuk tes yang Anda tanyakan dalam pertanyaan Anda, saya membuat test-bed berikut:
IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
TestID INT NOT NULL
PRIMARY KEY
IDENTITY(1,1)
, A INT NOT NULL
, B FLOAT NOT NULL
, C MONEY NOT NULL
, D BIGINT NOT NULL
);
INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
, sys.objects o4;
SELECT COUNT(1)
FROM #SomeTest;
Ini mengembalikan jumlah 260.144.641 pada mesin saya.
Untuk menguji metode "penambahan", saya menjalankan:
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;
Tab pesan menunjukkan:
Tabel '#SomeTest'. Pindai hitungan 3, pembacaan logis 1322661, pembacaan fisik 0, pembacaan maju 1313877, pembacaan logis lob 0, pembacaan fisik lob 0, pembacaan pembacaan lob depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 49047 ms, waktu yang berlalu = 173451 ms.
Untuk tes "kolom diskrit":
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
AND st.B = 0
AND st.C = 0
AND st.D = 0;
GO
SET STATISTICS IO, TIME OFF;
lagi, dari tab pesan:
Tabel '#SomeTest'. Pindai hitungan 3, pembacaan logis 1322661, pembacaan fisik 0, pembacaan maju 1322661, pembacaan logis lob 0, pembacaan fisik lob 0, pembacaan pemb lob depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 8938 ms, waktu yang berlalu = 162581 ms.
Dari statistik di atas Anda dapat melihat varian kedua, dengan kolom diskrit dibandingkan dengan 0, waktu yang berlalu sekitar 10 detik lebih pendek, dan waktu CPU sekitar 6 kali lebih sedikit. Durasi lama dalam pengujian saya di atas sebagian besar merupakan hasil dari membaca banyak baris dari disk. Jika Anda menurunkan jumlah baris menjadi 3 juta, Anda melihat rasio tetap hampir sama tetapi waktu yang berlalu turun secara nyata, karena disk I / O memiliki efek yang jauh lebih sedikit.
Dengan metode "Tambahan":
Tabel '#SomeTest'. Pindai hitungan 3, pembacaan logis 15255, pembacaan fisik 0, pembacaan read-forward 0, pembacaan logis lob 0, pembacaan fisik lob 0, pembacaan lob baca-depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 499 ms, waktu yang berlalu = 256 ms.
Dengan metode "kolom diskrit":
Tabel '#SomeTest'. Pindai hitungan 3, pembacaan logis 15255, pembacaan fisik 0, pembacaan read-forward 0, pembacaan logis lob 0, pembacaan fisik lob 0, pembacaan lob baca-depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 94 ms, waktu yang berlalu = 53 ms.
Apa yang akan membuat perbedaan yang sangat besar untuk tes ini? Indeks yang sesuai, seperti:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
Metode "penambahan":
Tabel '#SomeTest'. Pindai hitungan 3, bacaan logis 14235, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 546 ms, waktu yang berlalu = 314 ms.
Metode "kolom diskrit":
Tabel '#SomeTest'. Pindai hitungan 1, bacaan logis 3, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Waktu Eksekusi SQL Server: Waktu CPU = 0 ms, waktu yang berlalu = 0 ms.
Rencana eksekusi untuk setiap permintaan (dengan indeks di atas di tempat) cukup jelas.
Metode "penambahan", yang harus melakukan pemindaian seluruh indeks:
dan metode "kolom diskrit", yang dapat mencari ke baris pertama indeks di mana kolom indeks utama A
, adalah nol: