Ini adalah pertanyaan spin-off dari Urutan urutan yang ditentukan dalam kunci utama, namun penyortiran dieksekusi pada SELECT .
@Catcall mengatakan ini tentang masalah urutan penyimpanan (indeks berkerumun) dan urutan keluaran
Banyak orang percaya bahwa indeks berkerumun menjamin urutan pengurutan pada output. Tapi bukan itu yang dilakukannya; itu menjamin pesanan penyimpanan pada disk. Lihat, misalnya, posting blog ini .
Saya telah membaca posting blog oleh Hugo Kornelis dan memahami bahwa indeks tidak menjamin bahwa server sql membaca catatan dalam urutan tertentu. Namun saya mengalami kesulitan menerima bahwa saya tidak dapat menganggap ini untuk skenario saya?
CREATE TABLE [dbo].[SensorValues](
[DeviceId] [int] NOT NULL,
[SensorId] [int] NOT NULL,
[SensorValue] [int] NOT NULL,
[Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED
(
[DeviceId] ASC,
[SensorId] ASC,
[Date] DESC
) WITH (
FILLFACTOR=75,
DATA_COMPRESSION = PAGE,
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [MyPartitioningScheme]([Date])
Permintaan asli saya adalah ini:
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Tetapi saya menyarankan agar saya bisa menggunakan yang ini (baca penjelasan saya di bawah):
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
Seperti yang Anda lihat, baris tabel saya kecil (16bytes) dan saya hanya punya satu indeks, berkerumun. Dalam skenario saya, tabel terdiri dari 100.000.000 catatan saat ini (dan ini kemungkinan besar akan meningkat sepuluh kali lipat).
Ketika server basis data kueri tabel ini memiliki dua cara untuk menemukan baris saya, baik itu mencari kunci utama dan dengan demikian membaca dan mengembalikan nilai-nilai saya dalam desc. urutan Tanggal, atau harus melakukan pemindaian tabel penuh. Kesimpulan saya adalah bahwa pemindaian tabel penuh pada semua catatan itu akan terlalu lambat dan karena itu server database akan selalu mencari tabel melalui kunci primernya dan dengan demikian mengembalikan nilai yang diurutkan berdasarkanDate DESC
ORDER BY
di sana, maka Anda tahu Anda bisa mengandalkannya. Lihat # 3 di siniORDER BY
klausa itu merupakan hit kinerja besar bagi saya (baca pertanyaan lain untuk info lebih lanjut). Saya memiliki solusi yang berfungsi untuk saat ini, tetapi tidak akan bertahan kapan dan jika traffic saya meningkat.ORDER BY
klausa dalam kueri Anda. Ini berlaku untuk SQL Server , Oracle , MySQL , dan RDBMS lainnya yang dapat Anda pikirkan. Cobalah hal lain dan Anda menyiapkan secangkir FAIL kejutan.Jawaban:
Biarkan saya mencoba menjelaskan mengapa Anda tidak harus melakukan itu, mengapa Anda tidak boleh berasumsi bahwa produk-SQL akan mengembalikan hasil yang ditetapkan dalam urutan tertentu, kecuali Anda menentukannya, indeks apa pun - berkerumun atau tidak berkerumun, pohon-B atau R-Trees atau kd-tree atau fractal-tree atau apa pun indeks eksotis lainnya yang digunakan DBMS.
Kueri asli Anda memberi tahu DBMS untuk mencari
SensorValues
tabel, menemukan baris yang cocok dengan 3 kondisi, memesannya denganDate
menurun, tetap hanya baris pertama dari itu dan - akhirnya - pilih dan kembalikan hanyaSensorValue
kolom.Ini adalah perintah yang sangat spesifik yang telah Anda berikan ke DBMS dan hasilnya kemungkinan besar akan sama setiap kali Anda menjalankan kueri (ada kemungkinan itu tidak, jika Anda memiliki lebih dari satu baris yang cocok dengan kondisi dan memiliki yang sama maks
Date
tetapi berbedaSensorValue
tetapi mari kita asumsikan selama sisa percakapan bahwa tidak ada baris seperti itu di tabel Anda).Apakah DBMS harus melakukan ini, untuk menjalankan kueri ini, cara persis yang saya jelaskan di atas? Tidak, tentu saja tidak dan Anda tahu itu. Mungkin tidak membaca tabel tetapi membaca dari indeks. Atau mungkin menggunakan dua indeks jika dianggap lebih baik (lebih cepat). Atau tiga. Atau mungkin menggunakan hasil yang di-cache (bukan SQL Server tetapi hasil query cache DBMS lainnya). Atau mungkin menggunakan eksekusi paralel satu kali dan bukan kali berikutnya dijalankan. Atau ... (tambahkan fitur lain yang memengaruhi rencana eksekusi dan eksekusi).
Apa yang dijamin adalah bahwa itu akan mengembalikan hasil yang sama persis, setiap kali Anda menjalankannya - selama tidak ada baris yang dimasukkan, dihapus atau diperbarui.
Sekarang mari kita lihat apa yang dikatakan saran Anda:
Kueri ini memberi tahu DBMS untuk mencari
SensorValues
tabel, menemukan baris yang cocok dengan 3 kondisi,memesannya dengantidak peduli dengan pesanan, tetap hanya satu baris dan - akhirnya - pilih dan kembalikan hanyaDate
menurun,,SensorValue
kolom.Jadi, itu pada dasarnya mengatakan sama dengan yang pertama, kecuali bahwa itu memberitahu Anda ingin satu hasil saja yang cocok dengan kondisi dan Anda tidak peduli yang mana .
Sekarang, dapatkah kita berasumsi bahwa itu akan selalu memberikan hasil yang sama karena indeks berkerumun?
- Jika menggunakan indeks klaster ini setiap waktu, ya.
Tetapi apakah itu akan menggunakannya?
- Tidak.
Kenapa tidak?
- Karena bisa. Pengoptimal kueri bebas memilih jalur eksekusi setiap kali menjalankan pernyataan. Apa pun jalan yang menurutnya cocok untuk pernyataan itu.
Tapi bukankah menggunakan indeks berkerumun cara terbaik / tercepat untuk mendapatkan hasil?
- Tidak, tidak selalu. Mungkin ini pertama kalinya Anda menjalankan kueri. Kedua kalinya, mungkin menggunakan hasil cache (jika DBMS memiliki fitur seperti itu, bukan SQL Server * ). 1000 kali hasil mungkin telah dihapus dari cache dan hasil lain mungkin ada di sana. Katakanlah, Anda telah mengeksekusi kueri ini sebelum:
dan hasil yang di-cache (dari kueri di atas) adalah yang lain, berbeda yang masih cocok dengan kondisi Anda tetapi bukan yang pertama dalam pemesanan (yang diinginkan) Anda. Dan Anda telah mengatakan kepada DBMS untuk tidak peduli dengan pesanan.
OK, jadi hanya cache yang dapat memengaruhi ini?
- Tidak, banyak hal lain juga.
*: SQL Server tidak men-cache hasil pencarian tetapi Edisi Enterprise memang memiliki fitur Pemindaian Lanjutan yang agak mirip sehingga Anda bisa mendapatkan hasil yang berbeda karena kueri bersamaan. Tidak yakin persis kapan ini menendang. (thnx @Martin Smith untuk tipnya.)
Saya harap Anda yakin bahwa Anda tidak boleh mengandalkan bahwa permintaan SQL akan mengembalikan hasil dalam urutan tertentu, kecuali jika Anda menetapkan demikian. Dan jangan pernah gunakan
TOP (n)
tanpaORDER BY
, kecuali tentu saja Anda hanya ingin n baris dalam hasil dan Anda tidak peduli mana yang dikembalikan.sumber