Baru-baru ini saya menjelaskan kepada rekan-rekan tentang pentingnya memiliki kolom yang digunakan untuk mengurutkan data dalam tabel database jika perlu, misalnya untuk data yang dipesan secara kronologis. Ini terbukti agak sulit karena mereka bisa menjalankan kembali kueri mereka tanpa henti dan selalu akan mengembalikan rangkaian baris yang sama dalam urutan yang sama.
Saya telah memperhatikan ini sebelumnya dan semua yang bisa saya lakukan adalah bersikeras bahwa mereka mempercayai saya dan tidak hanya berasumsi bahwa tabel database akan berperilaku seperti file CSV atau Excel tradisional.
Misalnya, menjalankan kueri (PostgreSQL)
create table mytable (
id INTEGER PRIMARY KEY,
data TEXT
);
INSERT INTO mytable VALUES
(0, 'a'),
(1, 'b'),
(2, 'c'),
(3, 'd'),
(4, 'e'),
(5, 'f'),
(6, 'g'),
(7, 'h'),
(8, 'i'),
(9, 'j');
akan membuat tabel dengan urutan konseptual yang jelas. Memilih data yang sama dengan cara paling sederhana adalah:
SELECT * FROM mytable;
Selalu memberi saya hasil berikut:
id | data
----+------
0 | a
1 | b
2 | c
3 | d
4 | e
5 | f
6 | g
7 | h
8 | i
9 | j
(10 rows)
Saya bisa melakukan ini berulang-ulang dan itu akan selalu mengembalikan kepada saya data yang sama dalam urutan yang sama. Namun saya tahu bahwa urutan implisit ini dapat dipatahkan, saya telah melihatnya sebelumnya, terutama dalam dataset besar, di mana beberapa nilai acak akan terlempar ke tempat "salah" ketika dipilih. Tetapi saya sadar bahwa saya tidak tahu bagaimana ini terjadi atau bagaimana memperbanyaknya. Saya merasa sulit untuk mendapatkan hasil di Google karena permintaan pencarian cenderung hanya mengembalikan bantuan umum pada pengurutan set hasil.
Jadi, pertanyaan saya pada dasarnya adalah ini:
Bagaimana saya dapat membuktikan dan secara konkret membuktikan bahwa urutan pengembalian baris dari permintaan tanpa
ORDER BY
pernyataan tidak dapat diandalkan, lebih disukai dengan menyebabkan dan menampilkan rincian urutan implisit bahkan ketika tabel tersebut tidak diperbarui atau diedit ?Apakah ada bedanya sama sekali jika data hanya dimasukkan sekali secara massal dan kemudian tidak pernah diperbarui lagi?
Saya lebih suka jawaban berbasis postgres karena itu yang paling saya kenal tetapi saya lebih tertarik pada teori itu sendiri.
order by
klausa ke pertanyaan mereka? Apakah mereka mencoba menghemat penyimpanan kode sumber? keausan keyboard? waktu yang dibutuhkan untuk mengetik klausa yang ditakuti?Jawaban:
Saya melihat tiga cara untuk mencoba meyakinkan mereka:
Biarkan mereka mencoba kueri yang sama tetapi dengan tabel yang lebih besar (lebih banyak jumlah baris) atau ketika tabel diperbarui di antara eksekusi. Atau baris baru dimasukkan dan beberapa yang lama dihapus. Atau indeks ditambahkan atau dihapus di antara eksekusi. Atau meja disedot (dalam Postgres). Atau indeks dibangun kembali (dalam SQL Server). Atau tabel diubah dari berkerumun menjadi tumpukan. Atau layanan basis data dimulai kembali.
Anda dapat menyarankan agar mereka membuktikan bahwa eksekusi yang berbeda akan mengembalikan urutan yang sama. Bisakah mereka membuktikannya? Bisakah mereka memberikan serangkaian tes yang membuktikan bahwa permintaan apa pun akan memberikan hasil dalam urutan yang sama, tidak peduli berapa kali dieksekusi?
Berikan dokumentasi berbagai DBMS dalam hal itu. Sebagai contoh:
PostgreSQL :
SQL Server :
Oracle :
sumber
ORDER BY
, yang akan menjamin pesanan, tidak peduli bagaimana tabel akan berubah ? Mengapa tidak menambahkan brankas, yang tidak membahayakan?Ini adalah cerita angsa hitam lagi. Jika Anda belum melihatnya, itu tidak berarti mereka tidak ada. Mudah-mudahan dalam kasus Anda itu tidak akan menyebabkan krisis keuangan lain di seluruh dunia, hanya untuk beberapa pelanggan yang tidak bahagia.
Dokumentasi Postgres mengatakan ini secara eksplisit:
"Sistem" dalam hal ini terdiri dari daemon postgres itu sendiri (termasuk implementasi metode akses data dan pengoptimal kueri), sistem operasi yang mendasarinya, tata letak logis dan fisik dari penyimpanan basis data, bahkan mungkin cache CPU. Karena Anda sebagai pengguna basis data tidak memiliki kendali atas tumpukan itu, Anda tidak boleh mengandalkannya terus berperilaku selamanya seperti saat ini.
Rekan-rekan Anda melakukan kesalahan generalisasi yang terburu - buru . Untuk menyanggah pendapat mereka, cukup menunjukkan bahwa anggapan mereka salah hanya sekali, misalnya oleh dbfiddle ini .
sumber
Perhatikan contoh berikut, di mana kami memiliki tiga tabel terkait. Pesanan, Pengguna, dan Rincian Pesanan. OrderDetails ditautkan dengan kunci asing ke tabel Pesanan dan Tabel Pengguna. Ini pada dasarnya adalah pengaturan yang sangat khas untuk database relasional; bisa dibilang seluruh tujuan DBMS relasional .
Di sini, kami menanyakan tabel OrderDetails di mana UserID 15:
Output dari kueri terlihat seperti:
Seperti yang Anda lihat, urutan output baris tidak cocok dengan urutan baris dalam tabel OrderDetails.
Menambahkan eksplisit
ORDER BY
memastikan baris akan dikembalikan ke klien dalam urutan yang diinginkan:Jika urutan baris sangat penting, dan teknisi Anda tahu bahwa urutan itu penting, mereka seharusnya hanya ingin menggunakan
ORDER BY
pernyataan, karena mungkin mereka akan dikenakan biaya penunjukan jika ada kegagalan terkait dengan urutan yang salah.Contoh kedua, mungkin lebih instruktif, menggunakan
OrderDetails
tabel dari atas, di mana kami tidak bergabung dengan tabel lain, tetapi memiliki persyaratan sederhana untuk menemukan baris yang cocok dengan OrderID dan UserID, kami melihat masalahnya.Kami akan membuat indeks untuk mendukung kueri, seperti yang mungkin Anda lakukan di kehidupan nyata jika kinerja sangat penting (kapan bukan?).
Inilah pertanyaannya:
Dan hasilnya:
Menambahkan
ORDER BY
klausa pasti akan memastikan kita mendapatkan jenis yang benar di sini juga.Mock-up ini hanyalah contoh sederhana di mana baris tidak dijamin "berurutan" tanpa
ORDER BY
pernyataan eksplisit . Ada banyak lagi contoh seperti ini, dan karena kode mesin DBMS sering berubah, perilaku spesifik dapat berubah seiring waktu.sumber
Sebagai contoh praktis, di Postgres, urutan saat ini berubah ketika Anda memperbarui baris:
Saya tidak berpikir aturan pemesanan implisit yang ada ini didokumentasikan di mana saja, pasti dapat berubah tanpa pemberitahuan, dan jelas bukan perilaku portabel di mesin DB.
sumber
bukan demo, tapi terlalu lama untuk komentar.
Pada tabel besar beberapa basis data akan melakukan pemindaian paralel berselang-seling:
Jika dua kueri ingin memindai tabel yang sama, dan tiba di waktu yang hampir bersamaan, yang pertama mungkin sebagian jalan melalui tabel saat yang kedua dimulai.
Kueri kedua bisa menerima catatan mulai dari tengah tabel (saat kueri pertama selesai) dan kemudian menerima catatan dari awal tabel.
sumber
Buat indeks berkerumun yang memiliki urutan "salah". Misalnya, klaster aktif
ID DESC
. Ini akan sering menghasilkan urutan terbalik (meskipun ini juga tidak dijamin).sumber