CURRENT_TIMESTAMP สามารถใช้เป็นคีย์หลักได้หรือไม่


10

สามารถCURRENT_TIMESTAMPใช้เป็นPRIMARY KEY?

มีความเป็นไปได้ที่ INSERT ที่แตกต่างกันสองใบขึ้นไปเหมือนกันCURRENT_TIMESTAMPหรือไม่


3
ฉันได้ยินแอปที่เขียนโดยใช้การประทับเวลาเป็น PK ย้อนกลับไปในปี 1990 สิบปีต่อมาพีซีเริ่มเร็วขึ้นและมีการบันทึกเวลาซ้ำ สิ่งนี้ทำให้เกิดปัญหาร้ายแรงมากเนื่องจากการทำงานของแอพมีความสำคัญอย่างยิ่ง นอกจากนี้ยังมีการบังคับใช้เอกลักษณ์ PK อย่างไม่ถูกต้องตลอดทั้งแอป
Victor Di Leo

มีความเป็นไปได้ที่ INSERT ที่แตกต่างกันสองรายการขึ้นไปรับ CURRENT_TIMESTAMP เดียวกันหรือไม่ มีเพียงหนึ่งแบบสอบถามที่แทรก 2 ระเบียนสำหรับการชนกัน ดังนั้นคำตอบสำหรับคำถามเรื่องคือ "ไม่"
Akina


3
ฉันอยากรู้ว่าทำไมคุณต้องการสิ่งนี้?
Nanne

@Nanne ฉันสงสัยว่านี้: MySQL มีการจัดการที่ดีมากโดยอัตโนมัติจำนวนเต็มรหัส (เพียงแค่ auto_increment คุณลักษณะไปยังเขตข้อมูล) PostgreSQL ไม่ได้มีประเภทซีเรียลซึ่งมีความสวยงามน้อยกว่ามาก
peterh - Reinstate Monica

คำตอบ:


18

ตามเอกสารความแม่นยำของCURRENT_TIMESTAMPmicroseconds ดังนั้นความน่าจะเป็นของการชนนั้นต่ำ แต่เป็นไปได้

ตอนนี้ลองนึกภาพข้อผิดพลาดที่เกิดขึ้นน้อยมากและทำให้เกิดข้อผิดพลาดของฐานข้อมูล การ debug นั้นยากแค่ไหน? มันเป็นข้อผิดพลาดที่เลวร้ายยิ่งกว่าสิ่งใดสิ่งหนึ่งที่กำหนดไว้อย่างน้อยที่สุด

บริบทที่กว้างขึ้น: คุณอาจต้องการหลีกเลี่ยงความแตกต่างเล็กน้อยเหล่านี้ด้วยลำดับซึ่งน่ารำคาญเป็นพิเศษหากคุณคุ้นเคยกับ MySQL

นอกจากนี้หากคุณใช้ธุรกรรม (เฟรมเวิร์กเว็บส่วนใหญ่โดยเฉพาะอย่างยิ่ง Java ให้ทำ!) ดังนั้นการประทับเวลาจะเหมือนกันในการทำธุรกรรม! การสาธิต:

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)

แล้วพบกันใหม่? สองตัวเลือกผลลัพธ์เดียวกันทั้งหมด ฉันไม่พิมพ์เร็วนัก ;-)

-

หากคุณต้องการ ID ได้อย่างง่ายดายหลีกเลี่ยงการใช้ลำดับแล้วสร้างค่าแฮชจากตัวระบุที่แท้จริงของระเบียน ตัวอย่างเช่นหากฐานข้อมูลของคุณมีมนุษย์และคุณรู้ว่าวันเกิดของพวกเขาชื่อนามสกุลเดิมของแม่และชื่อจริงระบุพวกเขาโดยเฉพาะแล้วใช้

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

ในฐานะ id นอกจากนั้นคุณสามารถใช้CreationDateคอลัมน์หลังจากสิ่งที่คุณทำดัชนีตาราง แต่ไม่ใช่กุญแจ (ซึ่งเป็นรหัส)

ปล. โดยทั่วไปมันเป็นวิธีปฏิบัติที่ดีมากที่จะทำให้ DB ของคุณนั้นถูกกำหนดไว้อย่างดีที่สุดเท่าที่จะเป็นไปได้ คือการดำเนินการเดียวกันควรจะสร้างตรงเปลี่ยนแปลงเดียวกันใน DB ID ที่ใช้การประทับเวลาใด ๆ จะล้มเหลวคุณลักษณะที่สำคัญนี้ ถ้าคุณต้องการดีบักหรือจำลองอะไร คุณเล่นซ้ำการดำเนินการและวัตถุเดียวกันจะถูกสร้างขึ้นด้วยรหัสที่แตกต่างกัน ... มันยากที่จะปฏิบัติตามจริง ๆ และมันใช้เวลาทำงานมาก

Ps2 ใครก็ตามที่ตรวจสอบรหัสของคุณในอนาคตจะไม่มีความคิดเห็นที่ดีที่สุดที่จะเห็นรหัสที่สร้างจากการประทับเวลาด้วยเหตุผลข้างต้น


แม้ว่าคุณจะไม่ได้ใช้ธุรกรรม แต่จริงๆแล้วคุณกำลังใช้ธุรกรรม (เนื่องจาก Postgres ไม่มีโหมดไม่มีธุรกรรม แต่เพียงแค่มีการลงทะเบียนอัตโนมัติ) ดังนั้นถ้าคุณทำของหลายแถวพวกเขาทุกคนได้รับเหมือนกันINSERT current_timestampแล้วคุณก็มีทริกเกอร์ ...
เควิน

2
ฉันเคยได้ยินเกี่ยวกับแอพที่ยากจนเพราะผู้ชาย 2 คนมีชื่อเดียวกันและเกิดในวันเดียวกันและชื่อแม่ของพวกเขาเหมือนกัน อุ๊ยตาย หากมันเกิดขึ้นมันจะเกิดขึ้นไม่ช้าก็เร็ว
Balazs Gunics

@ BalazsGunics Helló :-) มันเป็นเพียงตัวอย่าง ตัวอย่างเช่นในสถานการณ์จริงฉันคิดว่า id เป็นที่อยู่อีเมลหรือชื่อผู้ใช้ที่เลือก (ซึ่งสามารถลงทะเบียนได้หากไม่มีอยู่) ก็เพียงพอแล้ว รัฐบาลมีแนวโน้มที่จะใช้หมายเลขประจำตัวส่วนบุคคลเช่น 1 870728 0651 สิ่งที่สำคัญคือการผูก id เข้ากับการประทับเวลาหรือค่าสุ่มเป็นการปฏิบัติที่ไม่ดีเพราะมันทำให้ DB ด้อยค่าลง
peterh - Reinstate Monica

@ BalazsGunics นอกจากนั้นคนสองคนที่มี mother_name + Given_name + วันเกิดเดียวกันก็อาจทำให้เกิดข้อผิดพลาดที่กำหนดขึ้นได้ การชนกันของคีย์หลักเนื่องจากธุรกรรมสองรายการที่มีการแทรกเกิดขึ้นในไมโครวินาทีเดียวกันมันยังคงเป็นปัญหาที่ไม่สามารถกำหนดได้และไม่สามารถทำซ้ำได้
peterh - Reinstate Monica

10

ไม่ใช่เพราะ CURRENT_TIMESTAMP เป็นไปได้ที่จะให้ค่าที่เหมือนกันสองค่าสำหรับ INSERT สองรายการถัดไป (หรือ INSERT เดียวที่มีหลายแถว)

ใช้เวลาตาม UUID แทน: uuid_generate_v1mc ()


7

พูดอย่างเคร่งครัด: ไม่เพราะCURRENT_TIMESTAMPเป็นฟังก์ชันและคอลัมน์ตารางอย่างน้อยหนึ่งคอลัมน์เท่านั้นที่สามารถสร้างPRIMARY KEYข้อ จำกัด ได้

ถ้าคุณหมายถึงการสร้างPRIMARY KEYข้อ จำกัด ในคอลัมน์ที่มีค่าเริ่มต้นCURRENT_TIMESTAMPแล้วคำตอบคือ: ใช่คุณสามารถ ไม่มีอะไรขัดขวางไม่ให้คุณทำเช่นเดียวกับที่คุณห้ามไม่ให้แอปเปิ้ลยิงจากหัวลูกชายของคุณ คำถามยังไม่สมเหตุสมผลในขณะที่คุณไม่ได้กำหนดวัตถุประสงค์ของมัน ข้อมูลประเภทใดที่ควรเก็บไว้ในคอลัมน์และตาราง คุณพยายามใช้กฎอะไร

โดยทั่วไปแล้วแนวคิดจะเชื่อมโยงกับข้อผิดพลาดคีย์ซ้ำเนื่องจากCURRENT_TIMESTAMPเป็นSTABLEฟังก์ชันที่ส่งคืนค่าเดียวกันสำหรับธุรกรรมเดียวกัน (เวลาเริ่มต้นของธุรกรรม) INSERT หลายรายการในธุรกรรมเดียวกันถูกผูกไว้เพื่อชน - เหมือนคำตอบอื่น ๆ ที่แสดงไว้แล้ว คู่มือ:

เนื่องจากฟังก์ชั่นเหล่านี้ส่งคืนเวลาเริ่มต้นของการทำธุรกรรมปัจจุบันค่าของพวกเขาจึงไม่เปลี่ยนแปลงในระหว่างการทำธุรกรรม นี่ถือเป็นคุณลักษณะ: เจตนาคือเพื่อให้การทำธุรกรรมครั้งเดียวมีความคิดที่สอดคล้องกันของเวลา“ ปัจจุบัน” เพื่อให้การแก้ไขหลายรายการภายในธุรกรรมเดียวกันมีการประทับเวลาเดียวกัน

การประทับเวลาภายหลังถูกใช้เป็นจำนวนเต็ม 8 ไบต์ซึ่งแสดงเศษส่วนได้ถึง 6 หลัก (ความละเอียดไมโครวินาที)

หากคุณกำลังสร้างตารางที่ควรจะถือไม่เกินหนึ่งแถวต่อวินาทีและมีเงื่อนไขว่าจะไม่เกิดการเปลี่ยนแปลง (สิ่งที่ชื่อsensor_reading_per_microsecond) แล้วก็อาจจะทำให้ความรู้สึก แถวซ้ำควรเพิ่มข้อผิดพลาดการละเมิดคีย์ซ้ำ นั่นเป็นข้อยกเว้นที่แปลกใหม่ และประเภทข้อมูลtimestamptz(ไม่timestamp) อาจจะดีกว่า ดู:

ฉันจะยังคงใช้คีย์หลักอนุกรมแทนแทน และเพิ่มUNIQUEข้อ จำกัด ในคอลัมน์การประทับเวลา ลดความยุ่งยากที่อาจเกิดขึ้นได้โดยไม่ต้องพึ่งพารายละเอียดการปฏิบัติของ RDBMS


แม้sensor_reading_per_microsecondอาจชนกันหากคุณไม่สามารถรับประกันได้ว่าเวลาของการอ่านแต่ละครั้งจะถูกซิงโครไนซ์อย่างสมบูรณ์แบบเมื่อเทียบกับการอ่านก่อนหน้า ส่วนเบี่ยงเบน sub-microsecond (ซึ่งมักจะเป็นไปไม่ได้) แบ่งโครงการ โดยทั่วไปแล้วฉันยังคงหลีกเลี่ยงปัญหานี้โดยสิ้นเชิง (โปรดทราบว่าในกรณีเช่นนี้การชนที่เกิดขึ้นอาจเป็นที่ต้องการ!)
การแข่งขัน Lightness ใน Orbit

@ ความสว่าง: ฉันอยู่ในข้อตกลงที่สมบูรณ์ ตัวอย่างของคุณด้วยการเปลี่ยนเวลาโดยไม่ตั้งใจหลังจากการเบี่ยงเบนเล็ก ๆ
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.