Urutan penyimpanan vs Urutan hasil

8

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

m__
sumber
2
Mengapa Anda ingin dapat mengandalkan asumsi ini begitu buruk? Mengapa Anda tidak meletakkan saja ORDER BYdi sana, maka Anda tahu Anda bisa mengandalkannya. Lihat # 3 di sini
Aaron Bertrand
Karena 2 alasan, keingintahuan dan karena ORDER BYklausa 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.
m__
1
ORDER BY seharusnya tidak menjadi hit kinerja jika Anda mengandalkan pesanan yang Anda lihat tanpa pesanan - itu tidak masuk akal bagi saya.
Aaron Bertrand
4
Satu- satunya hal yang menjamin urutan hasil adalah ORDER BYklausa 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.
Nick Chammas

Jawaban:

15

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 SensorValuestabel, menemukan baris yang cocok dengan 3 kondisi, memesannya dengan Datemenurun, tetap hanya baris pertama dari itu dan - akhirnya - pilih dan kembalikan hanya SensorValuekolom.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

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 Datetetapi berbeda SensorValuetetapi 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:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Kueri ini memberi tahu DBMS untuk mencari SensorValuestabel, menemukan baris yang cocok dengan 3 kondisi, memesannya dengan Datemenurun,, tidak peduli dengan pesanan, tetap hanya satu baris dan - akhirnya - pilih dan kembalikan hanya SensorValuekolom.

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:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

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.

  • indeks lain dianggap, pada waktu itu oleh DBMS lebih baik untuk permintaan ini.
  • pengembang mengubah atau menghapus sepenuhnya indeks berkerumun yang Anda miliki ini.
  • Anda atau pengembang lain menambahkan indeks lain yang diputuskan pengoptimal itu lebih efisien untuk digunakan daripada CI.
  • Anda memperbarui ke versi baru dan pengoptimal baru memiliki bug kecil atau perubahan bagaimana peringkat dan memilih rencana eksekusi.
  • statistik diperbarui.
  • eksekusi paralel dipilih sebagai gantinya.

*: 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)tanpa ORDER BY, kecuali tentu saja Anda hanya ingin n baris dalam hasil dan Anda tidak peduli mana yang dikembalikan.

ypercubeᵀᴹ
sumber
2
SQL Server Enterprise Edition memang memiliki fitur Pemindaian Lanjutan yang agak mirip sehingga Anda bisa mendapatkan hasil yang berbeda karena kueri bersamaan. Tidak yakin persis kapan ini menendang.
Martin Smith
1
Hal lain yang berpotensi "mengacak" urutan hasil (bahkan jika kueri tampaknya didorong oleh indeks yang dipesan) adalah paralelisme. Saya melihat aplikasi yang telah dengan senang hati menjalankan SQL yang rusak mulai berperilaku buruk setelah mengaktifkan paralelisme otomatis (bukan SQL Server, tapi saya kira itu mungkin berlaku juga di sana).
Mat