Bisakah CURRENT_TIMESTAMP digunakan sebagai KUNCI UTAMA?

10

Dapat CURRENT_TIMESTAMPdigunakan sebagai PRIMARY KEY?

Apakah ada kemungkinan dua atau lebih INSERT yang berbeda, mendapatkan yang sama CURRENT_TIMESTAMP?

John Puskin
sumber
3
Saya mendengar tentang aplikasi yang diberi kode menggunakan cap waktu sebagai PK, di tahun 1990-an. Sepuluh tahun kemudian, PC menjadi lebih cepat dan cap waktu digandakan. Ini menyebabkan masalah yang sangat serius, karena fungsionalitas aplikasi sangat kritis. Keunikan PK juga tidak ditegakkan dengan baik di seluruh aplikasi.
Victor Di Leo
Apakah ada kemungkinan dua atau lebih INSERT berbeda, mendapatkan CURRENT_TIMESTAMP yang sama? Sudah cukup satu kueri dimasukkan 2 catatan untuk tabrakan. Jadi jawaban untuk pertanyaan subjek adalah "TIDAK".
Akina
3
Saya ingin tahu mengapa Anda menginginkan ini?
Nanne
@Nanne Saya menduga ini: MySQL memiliki penanganan yang sangat bagus dari id bilangan bulat yang bertambah secara otomatis (hanya atribut auto_increment ke bidang). PostgreSQL belum, ia memiliki tipe serial yang jauh lebih indah.
peterh

Jawaban:

18

Sesuai dokumentasi , ketepatan CURRENT_TIMESTAMPmikrodetik adalah. Dengan demikian, kemungkinan tabrakan rendah, tetapi mungkin.

Sekarang bayangkan sebuah bug yang terjadi sangat jarang, dan menyebabkan kesalahan database. Seberapa sulit untuk men-debug itu? Ini adalah bug yang jauh lebih buruk daripada yang setidaknya bersifat deterministik.

Konteks yang lebih luas: Anda mungkin ingin menghindari nuansa kecil ini dengan urutan, yang sangat mengganggu jika Anda terbiasa dengan MySQL.

Selain itu, jika Anda menggunakan transaksi (kebanyakan kerangka kerja web, terutama yang Java, lakukan!), Maka cap waktu akan sama di dalam transaksi! Demonstrasi:

postgres=# begin;
BEGIN
postgres=# select current_timestamp;
       current_timestamp       
-------------------------------
 2018-08-06 02:41:42.472163+02
(1 Zeile)

postgres=# select current_timestamp;
       current_timestamp       
-------------------------------
 2018-08-06 02:41:42.472163+02
(1 Zeile)

Sampai jumpa? Dua pilihan, hasil yang persis sama. Saya tidak mengetik begitu cepat. ;-)

-

Jika Anda ingin ID mudah, menghindari penggunaan urutan, kemudian menghasilkan beberapa nilai hash dari pengidentifikasi nyata catatan. Misalnya, jika database Anda memiliki manusia, dan Anda tahu bahwa tanggal lahir mereka, nama gadis ibu dan nama asli secara unik mengidentifikasi mereka, maka gunakan

md5(mother_name || '-' || given_name || '-' birthday);

sebagai id. Selain itu, Anda bisa menggunakan CreationDatekolom, setelah apa yang Anda indeks tabel, tetapi itu bukan kunci (yang merupakan id).

PS Secara umum, ini adalah praktik yang sangat baik untuk membuat DB Anda begitu deterministik, karena itu mungkin. Yaitu operasi yang sama harus membuat perubahan persis sama di DB . ID berbasis timestamp gagal fitur penting ini. Bagaimana jika Anda ingin men-debug atau mensimulasikan sesuatu? Anda memutar ulang operasi dan objek yang sama akan dibuat dengan id yang berbeda ... benar-benar tidak sulit untuk diikuti, dan menghemat banyak jam kerja.

Ps2 Siapa pun yang memeriksa kode Anda di masa depan, tidak akan memiliki pendapat terbaik melihat id yang dihasilkan timestamp, dengan alasan di atas.

peterh - Pasang kembali Monica
sumber
Bahkan jika Anda tidak menggunakan transaksi, Anda sebenarnya menggunakan transaksi (karena Postgres tidak memiliki mode tanpa transaksi, ia hanya memiliki autocommit). Jadi, jika Anda melakukan INSERTbeberapa baris, semuanya mendapatkan yang sama current_timestamp. Dan kemudian Anda memiliki pemicu ...
Kevin
2
Saya telah mendengar tentang aplikasi yang rusak karena 2 orang memiliki nama yang sama dan lahir pada hari yang sama dan nama ibu mereka identik. Aduh. Jika BISA terjadi itu AKAN terjadi, cepat atau lambat.
Balazs Gunics
@BalazsGunics Helló :-) Itu hanya contoh. Misalnya, dalam skenario nyata, saya pikir id sebagai alamat email atau nama pengguna yang dipilih (yang dapat didaftarkan hanya jika belum ada) sudah cukup. Pemerintah cenderung menggunakan beberapa nomor identifikasi pribadi, seperti 1 870728 0651. Yang penting, mengikat id ke stempel waktu atau ke nilai acak adalah praktik yang buruk, karena membuat DB lebih sedikit deterministik.
peterh
@BalazsGunics Selain itu, dua orang dengan nama mother_name + yang sama + ulang tahun + yang sama, itu akan menyebabkan masih kesalahan deterministik. Tabrakan kunci primer karena dua transaksi yang menyisipkan terjadi dalam mikrodetik yang sama, itu masih masalah non-deterministik, dan sangat sulit direproduksi.
peterh
10

Tidak juga karena CURRENT_TIMESTAMP mungkin memberikan dua nilai identik untuk dua INSERT berikutnya (atau satu INSERT dengan beberapa baris).

Gunakan UUID berbasis waktu sebagai gantinya: uuid_generate_v1mc () .

Linas
sumber
7

Sebenarnya: Tidak. Karena CURRENT_TIMESTAMPadalah fungsi dan hanya satu atau lebih kolom tabel yang dapat membentuk PRIMARY KEYkendala.

Jika Anda bermaksud membuat PRIMARY KEYbatasan pada kolom dengan nilai default CURRENT_TIMESTAMP, maka jawabannya adalah: Ya, Anda bisa . Tidak ada yang menghalangi Anda melakukannya, seperti tidak ada yang mencegah Anda menembak apel dari kepala putra Anda. Pertanyaannya tetap tidak masuk akal sementara Anda tidak mendefinisikan tujuan dari pertanyaan itu. Jenis data apa yang harus dimiliki oleh kolom dan tabel? Aturan apa yang Anda coba terapkan?

Biasanya, idenya pasti akan mengalami kesalahan kunci duplikat karena CURRENT_TIMESTAMPmerupakan STABLEfungsi yang mengembalikan nilai yang sama untuk transaksi yang sama (waktu mulai transaksi). Beberapa INSERT dalam transaksi yang sama pasti akan bertabrakan - seperti jawaban lain yang telah diilustrasikan. Manual:

Karena fungsi-fungsi ini mengembalikan waktu mulai dari transaksi saat ini, nilainya tidak berubah selama transaksi. Ini dianggap sebagai fitur: tujuannya adalah untuk memungkinkan satu transaksi memiliki gagasan yang konsisten tentang waktu "saat ini", sehingga beberapa modifikasi dalam transaksi yang sama memiliki cap waktu yang sama.

Stempel waktu Postgres diimplementasikan sebagai bilangan bulat 8-byte yang mewakili hingga 6 digit fraksional (resolusi mikrodetik).

Jika Anda membangun tabel yang seharusnya menampung tidak lebih dari satu baris per mikrodetik dan kondisi itu tidak akan berubah (sesuatu bernama sensor_reading_per_microsecond), maka mungkin masuk akal. Baris duplikat seharusnya meningkatkan kesalahan pelanggaran kunci duplikat. Itu pengecualian eksotis. Dan tipe data timestamptz(bukan timestamp) mungkin lebih disukai. Lihat:

Saya masih lebih suka menggunakan kunci primer serial pengganti sebagai gantinya. Dan tambahkan UNIQUEkendala pada kolom cap waktu. Lebih sedikit kemungkinan komplikasi, tidak bergantung pada detail implementasi RDBMS.

Erwin Brandstetter
sumber
Bahkan sensor_reading_per_microsecondmungkin berbenturan jika Anda tidak dapat benar-benar menjamin bahwa waktu setiap pembacaan disinkronkan dengan sempurna dengan yang sebelumnya; penyimpangan sub-mikrodetik (yang seringkali bukan tidak mungkin) mematahkan skema. Secara umum saya masih benar-benar menghindari ini. (Ingat, seperti yang Anda tunjukkan, dalam kasus seperti itu, tabrakan yang dihasilkan mungkin diinginkan!)
Lightness Races in Orbit
@ Cahaya: Saya setuju sepenuhnya. Contoh Anda dengan pergeseran waktu yang tidak disengaja setelah deviasi kecil bulat menggambarkan peringatan lain.
Erwin Brandstetter