Hal yang penting untuk dipahami adalah bahwa tabel SQL tidak memiliki urutan . Urutan baris yang Anda lihat saat Anda SELECT
tanpa ORDER BY
hanya tetap sama karena lebih cepat bagi database untuk mendapatkannya dalam urutan itu daripada urutan lainnya. PostgreSQL hanya akan mengembalikan baris dalam urutan ini ketika Anda melakukan pemindaian berurutan pada tabel; jika dapat menggunakan indeks untuk kueri maka Anda biasanya akan mendapatkan baris dalam urutan lain.
Anda mungkin menemukan jawaban yang saya tulis ini informatif sebelumnya.
Di PostgreSQL, UPDATE
s ke baris dapat memindahkannya ke lokasi berbeda di dalam tabel, mengubah urutan pengembaliannya. Begitu juga proses autovacuum latar belakang dan berbagai operasi lain seperti VACUUM
dan CLUSTER
.
Jadi Anda harus tidak pernah mengandalkan pemesanan "default" untuk apa pun. Jika Anda ingin memberi baris semacam urutan, mereka harus memiliki kunci untuk mengurutkannya.
Jika Anda telah membuat tabel tanpa kunci dan sekarang menyadari bahwa seharusnya memilikinya, Anda mungkin dapat memulihkan dari situasi tersebut dengan menggunakan ctid
kolom sistem. Jangan jangan mengandalkan ini untuk penggunaan produksi, ini adalah kolom internal sistem yang hanya dapat dilihat oleh pengguna untuk tujuan pemulihan dan diagnostik darurat. Pertama, lihat apakah pemesanan fisik di disk benar-benar sesuai dengan yang Anda inginkan:
SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;
Jika ya, Anda dapat menambahkan kolom kunci baru yang telah disetel sebelumnya ke kunci yang bertambah otomatis yang diterapkan dalam urutan baris di disk. Ada dua cara untuk melakukan ini. Yang paling aman adalah:
BEGIN;
LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE;
ALTER TABLE mytable RENAME TO mytable_old;
CREATE TABLE mytable (id SERIAL PRIMARY KEY, LIKE mytable_old INCLUDING ALL);
INSERT INTO mytable
SELECT row_number() OVER () AS id, *
FROM mytable_old
ORDER BY ctid;
SELECT setval('mytable_id_seq', (SELECT max(id)+1 FROM mytable));
COMMIT;
lalu setelah Anda yakin Anda puas dengan hasilnya, DROP TABLE mytable_old;
. Lihat demo ini:http://sqlfiddle.com/#!12/2cb99/2
Cara cepat dan mudah tetapi kurang aman adalah dengan membuat kolom dan mengandalkan PostgreSQL untuk menulis ulang tabel dari awal hingga akhir:
ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;
sama sekali tidak ada jaminan bahwa PostgreSQL akan menetapkan ID secara berurutan, meskipun dalam praktiknya hal itu akan dilakukan. Lihat demo SQLFiddle ini.
Ketahuilah bahwa saat Anda menggunakan SEQUENCE
(yang merupakan SERIAL
kolom membuat) ada beberapa perilaku yang mungkin tidak Anda harapkan. Saat Anda menyisipkan beberapa baris sekaligus, baris mungkin tidak selalu mendapatkan ID yang ditetapkan dalam urutan yang tepat seperti yang Anda harapkan, dan baris tersebut mungkin "muncul" (menjadi terlihat) dalam urutan yang berbeda dengan urutan ID yang ditetapkan dan disisipkan masuk Juga, jika transaksi mundur, ID yang dihasilkan dibuang selamanya, sehingga Anda mendapatkan celah dalam penomoran. Ini sangat bagus jika Anda ingin database Anda cepat, tetapi tidak ideal jika Anda ingin penomoran tanpa celah. Jika itu yang Anda butuhkan, cari "postgresql gapless sequence".