มีวิธีใดบ้างในการหลีกเลี่ยงการทำซ้ำเมื่อคุณไม่สามารถเพิ่มดัชนีที่ไม่ซ้ำ


10

ฉันติดอยู่ในปัญหาที่เกิดขึ้นพร้อมกัน

เป็นปัญหาทั่วไปที่ผู้ใช้ส่งธุรกรรม 2 ถึง 3 เพื่อเก็บข้อมูลบางอย่างที่ไม่ควรทำซ้ำในฐานข้อมูลในกรณีที่มีการบันทึกซ้ำคุณควรส่งคืนข้อผิดพลาด

ปัญหานี้เป็นเรื่องง่ายเมื่อคุณสามารถเพิ่มดัชนี (เฉพาะ) ไปยังคอลัมน์ที่คุณเก็บแฮช

แต่ในกรณีนี้ฉันมีตารางขนาดใหญ่ (อาจเป็นล้านระเบียน) และฉันไม่สามารถแก้ไขตารางได้

ในความเป็นจริงเรามีคอลัมน์ที่เราเก็บแฮชของข้อมูลที่ไม่ควรทำซ้ำ แต่ไม่ได้ตั้งค่าดัชนีที่ไม่ซ้ำกัน

ฉันพยายามใช้รหัส java เพื่อตรวจสอบว่ามีอยู่ก่อนที่จะล้างข้อมูลยังคงได้รับซ้ำ

แนวทางแก้ไขที่เป็นไปได้สำหรับสิ่งนี้คือ:

  • สร้างทริกเกอร์ที่ตรวจสอบว่าแฮชที่ฉันพยายามแทรกมีอยู่แล้วบนโต๊ะ
  • สร้างตารางอื่นเพื่อเก็บดัชนีเฉพาะสำหรับตารางนี้และเพิ่ม foreign key ไปยังตารางหลัก
  • นั่งในตำแหน่งทารกในครรภ์และร้องไห้

คุณตรวจสอบแฮชที่ล้มเหลวเนื่องจากการชนกันของข้อมูลหรือข้อผิดพลาดในเช็คหรือไม่?
candied_orange

4
ฉันไม่ได้รับคำถามของคุณ ดังนั้นแทนที่จะจัดทำดัชนีหนึ่งครั้งสำหรับตารางใหญ่ทั้งหมดของคุณที่มีล้านเรคคอร์ดคุณต้องการอ่านสำหรับเรคคอร์ดล้านต่อไปที่คุณจะเพิ่มจำนวนล้านที่มีอยู่ในการค้นหาทวีคูณ? หรือทำซ้ำข้อมูลบางส่วนและเพิ่มตัวเชื่อมเพื่อทำการตรวจสอบของคุณ?
Christophe

ปัญหาคือสำหรับการเปลี่ยนแปลงนี้ฉันได้รับคำเตือนว่าเราต้องการพื้นที่จำนวนมากและการหยุดทำงานที่ยาวนานสำหรับบริการของเราเพื่อให้เป็นไปตามข้อกำหนดบางประการบริการของเราไม่สามารถหยุดลงได้มากกว่า 2 ชั่วโมงต่อเดือน ฉันรู้ว่าวิธีที่ดีที่สุดคือทำการบำรุงรักษาบนโต๊ะนี้ แต่เป็นสิ่งที่ฉันไม่สามารถทำได้ในขณะนี้ดังนั้นเราจึงต้องการวิธีแก้ปัญหา
rafuru

4
ฉันไม่เข้าใจ - ทำไมการเพิ่มทริกเกอร์หรือเพิ่มตารางอื่นสำหรับ "การลอกเลียนแบบ" ดัชนีใช้เวลาน้อยกว่าการเพิ่มดัชนีลงในตารางที่มีอยู่
Doc Brown

2
@rafuru: ใครบอกว่าคุณต้องสร้างดัชนีที่ไม่ซ้ำกัน? ดัชนีมาตรฐานที่ไม่ซ้ำกันอาจทั้งหมดที่คุณต้องการค้นหาแถวทั้งหมดที่มีค่าแฮชเดียวกันอย่างรวดเร็ว
Doc Brown

คำตอบ:


3

มีสถานการณ์ที่เป็นไปได้สองสามข้อซึ่งง่ายต่อการแก้ไขและสถานการณ์ที่อันตรายที่ไม่ใช่

สำหรับผู้ใช้ที่ป้อนค่าจากนั้นป้อนค่าเดียวกันในภายหลังในเวลาต่อมา SELECT แบบง่าย ๆ ก่อนที่ INSERT จะตรวจพบปัญหา สิ่งนี้ใช้ได้กับกรณีที่ผู้ใช้รายหนึ่งส่งค่าและต่อมาผู้ใช้รายอื่นส่งค่าเดียวกัน

หากผู้ใช้ส่งรายการค่าที่ซ้ำกัน - พูดว่า {ABC, DEF, ABC} - ในการเรียกใช้รหัสเดียวแอปพลิเคชันสามารถตรวจจับและกรองรายการที่ซ้ำกันซึ่งอาจทำให้เกิดข้อผิดพลาด คุณจะต้องตรวจสอบว่า DB ไม่มีค่าใด ๆ ที่ไม่ซ้ำกันก่อนการแทรก

สถานการณ์ที่ยุ่งยากคือเมื่อการเขียนของผู้ใช้คนหนึ่งอยู่ใน DBMS ในเวลาเดียวกันกับการเขียนของผู้ใช้คนอื่นและพวกเขากำลังเขียนค่าเดียวกัน จากนั้นคุณมีเงื่อนไขการแข่งขันระหว่างพวกเขา เนื่องจาก DBMS นั้นเป็นไปได้มากว่าคุณไม่ได้พูดว่าระบบใดที่คุณกำลังใช้งานอยู่ซึ่งเป็นระบบการทำงานหลายหน้าที่ที่สามารถทำงานได้ทุกช่วงเวลาในการดำเนินการ นั่นหมายความว่างานของ user1 สามารถตรวจสอบว่าไม่มีแถวที่มีอยู่แล้วงานของ user2 สามารถตรวจสอบว่าไม่มีแถวที่มีอยู่จากนั้นงานของ user1 สามารถแทรกแถวนั้นแล้วงานของ user2 สามารถแทรกแถวนั้นได้ ในแต่ละจุดงานมีความสุขเป็นรายบุคคลพวกเขากำลังทำสิ่งที่ถูกต้อง อย่างไรก็ตามข้อผิดพลาดเกิดขึ้นทั่วโลก

โดยทั่วไปแล้ว DBMS จะจัดการเรื่องนี้โดยการใส่ค่าที่เป็นปัญหา ในปัญหานี้คุณกำลังสร้างแถวใหม่ดังนั้นยังไม่มีอะไรล็อค คำตอบคือล็อคช่วง ตามที่แนะนำนี้จะล็อคช่วงของค่าไม่ว่าจะมีอยู่ในปัจจุบันหรือไม่ เมื่อล็อคช่วงที่ไม่สามารถเข้าถึงได้โดยงานอื่นจนกว่าจะปล่อยล็อค ที่จะได้รับล็อคช่วงที่คุณต้องระบุและระดับการแยกของSERIALIZABLE ปรากฏการณ์ของงานอีกด้อมในแถวหลังจากงานของคุณมีการตรวจสอบเป็นที่รู้เป็นบันทึกภาพหลอน

การตั้งค่าระดับการแยกเป็น Serializable ทั่วทั้งแอปพลิเคชันจะมีผลกระทบ ปริมาณงานจะลดลง เงื่อนไขการแข่งขันอื่น ๆ ที่ทำงานได้ดีพอในอดีตอาจเริ่มแสดงข้อผิดพลาดในขณะนี้ ฉันขอแนะนำให้ตั้งค่าบนการเชื่อมต่อซึ่งเรียกใช้งานโค้ดที่ซ้ำซ้อนของคุณและปล่อยให้ส่วนที่เหลือของแอปพลิเคชันเป็นเช่นเดิม

ทางเลือกที่ใช้รหัสคือการตรวจสอบหลังจากเขียนมากกว่าก่อน ดังนั้นทำ INSERT แล้วนับจำนวนแถวที่มีค่าแฮช หากมีการย้อนกลับการดำเนินการที่ซ้ำกัน สิ่งนี้อาจมีผลลัพธ์ที่ผิดปกติ พูดภารกิจที่ 1 เขียนจากนั้นภารกิจที่ 2 จากนั้นภารกิจที่ 1 จะตรวจสอบและค้นหาสำเนา มันย้อนกลับแม้ว่ามันจะเป็นครั้งแรก ในทำนองเดียวกันงานทั้งสองอาจตรวจพบการทำซ้ำและย้อนกลับทั้งสอง แต่อย่างน้อยคุณก็จะได้รับข้อความเพื่อใช้งานกลไกการลองใหม่และไม่มีรายการซ้ำใหม่ การย้อนกลับถูกดึงออกมาเหมือนใช้การยกเว้นเพื่อควบคุมการไหลของโปรแกรม ทราบดีว่าทุกคนงานในการทำธุรกรรมจะถูกย้อนกลับไม่ใช่เฉพาะการเขียนซ้ำ และคุณจะต้องมีธุรกรรมที่ชัดเจนซึ่งอาจลดการเกิดพร้อมกัน การตรวจสอบซ้ำจะช้าลงอย่างน่ากลัวเว้นแต่คุณจะมีดัชนีในแฮช หากคุณทำเช่นกันคุณอาจทำให้มันเป็นหนึ่งที่ไม่ซ้ำกัน!

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


2

ในความเป็นจริงเรามีคอลัมน์ที่เราเก็บแฮชของข้อมูลที่ไม่ควรทำซ้ำ แต่ไม่ได้ตั้งค่าดัชนีที่ไม่ซ้ำกัน

การตรวจสอบการชนกันกัญชาเป็นขั้นตอนแรกที่ดี แต่ระวังคุณไม่สามารถรับประกันโปรแกรมเดียวกันจะผลิตกัญชาเดียวกันบนข้อมูลเดียวกันหากมีการเริ่มต้นใหม่ ฟังก์ชันแฮช "เร็ว" จำนวนมากใช้ inngilt prng ซึ่งเริ่มต้นที่เวลาเริ่มต้นโปรแกรม ใช้แฮชการเข้ารหัสหากแฮชนั้นต้องเหมือนกันเสมอไม่ว่าจะทำอะไรเหมือนอย่างที่คุณทำในแอปพลิเคชันนี้ หมายเหตุคุณไม่ต้องการแฮชการเข้ารหัสลับที่ดีหรือปลอดภัย

ขั้นตอนที่สองคือการตรวจสอบความเท่าเทียมกันของข้อมูลเนื่องจากแม้แต่ฟังก์ชั่นแฮชที่ดีที่สุดบางครั้งก็อาจส่งผลให้เกิดการชนเนื่องจากคุณ (ปกติ) จะลดการเอนโทรปีของข้อมูลของคุณ

ดังนั้น:

ขั้นตอนที่ 1: ตรวจสอบว่าคุณได้รับการชนบนแฮชการเข้ารหัสหรือไม่

ขั้นตอนที่ 2: ถ้าแฮชตรงกันให้ตรวจสอบข้อมูลจริงเหมือนกัน


ฉันล้มเหลวในการดูว่าวิธีนี้ตอบคำถาม สมมุติว่าช่วงเวลาหนึ่งคอลัมน์แฮชที่มีอยู่เต็มไปด้วยฟังก์ชันแฮชที่กำหนดไว้ (มิฉะนั้นความพยายามที่จะใช้มันจะไม่มีเหตุผล) เพื่อความเข้าใจของฉันปัญหาคือไม่มีดัชนีในคอลัมน์ hash นั้นในฐานข้อมูลดังนั้นแม้แต่ขั้นตอนแรกในคำตอบของคุณ - ตรวจสอบว่ามีการชนกันหรือไม่ - ยังคงต้องการสแกนตารางเต็มสำหรับแต่ละระเบียนใหม่บนตารางด้วย หลายล้านบันทึกซึ่งอาจจะช้าเกินไป
Doc Brown

เป็นการดีที่สุดที่คุณสามารถทำได้โดยไม่สร้างดัชนีซึ่งเป็นคำถามที่ถาม อย่างน้อยการสแกนแฮชหมายความว่าคุณต้องตรวจสอบเพียงหนึ่งคอลัมน์เท่านั้นซึ่งเร็วกว่าการตรวจสอบอย่างมากอย่างไรก็ตามมีหลายคอลัมน์ที่ต้องตรวจสอบ
Turksarama

ฉันค่อนข้างแน่ใจว่าแม้ว่าจะไม่สามารถสร้างดัชนีได้ (ซึ่งในกรณีนี้อาจเป็นไปได้) คำแนะนำดั้งเดิมของ OPs ในการ " สร้างตารางอื่นเพื่อเก็บดัชนีเฉพาะสำหรับตารางนี้และเพิ่ม foreign key ไปยังตารางหลัก " ความรู้สึกมากขึ้น
Doc Brown

แฮชที่กำหนดและแฮชการเข้ารหัสเป็นแนวคิดสองแนวคิดที่พวกเขาไม่ได้? แฮชการเข้ารหัสอาจไม่สามารถกำหนดได้และในทางกลับกันแฮชที่กำหนดขึ้นอาจไม่ดีกับความแข็งแกร่งของการเข้ารหัส
Newtopian

พวกเขาไม่ได้เหมือนกัน แต่พวกเขาไม่ใช่ orthogonal เช่นกัน Cryptographic hash เป็นเซตย่อยของ hashes ที่กำหนดไว้ แต่ไม่มีใครรบกวนการสร้าง hashes ที่กำหนดค่าที่ไม่เข้ารหัสลับเว้นแต่ว่าคุณต้องการให้มันสามารถย้อนกลับได้ด้วยเหตุผลบางอย่าง
Turksarama

2

สร้างตารางใหม่ด้วยคีย์หลักที่ไม่ซ้ำกัน

บนฝั่งไคลเอ็นต์ให้เริ่มสร้าง GUID สำหรับแต่ละระเบียนเพื่อให้คุณสามารถตรวจสอบการส่งใหม่ได้ง่าย

ใส่ระเบียนใหม่ลงในตารางใหม่ดังนั้นอย่างน้อยคุณก็ดีสำหรับข้อมูลใหม่ที่เข้ามา

มีคอลัมน์ในตารางใหม่ "CheckedAgainstOldData"

มีงานแบ็กเอนด์ที่ทำสิ่งใดก็ตามที่คุณตรวจสอบแฮชช้าในปัจจุบันเพื่อดูว่าสามารถค้นหาข้อมูลที่ซ้ำกันในข้อมูลเก่าและตั้งค่าสถานะตามนั้นปฏิเสธรายการซ้ำที่จุดนี้ส่งการแจ้งเตือนกลับไปยังลูกค้า

ในขณะเดียวกันก็มีงานแบ็กเอนด์อื่นที่ย้ายข้อมูลจากเก่าไปยังตารางใหม่การตรวจสอบรายการซ้ำด้วยการตรวจสอบแฮชของคุณและสร้าง GUID

คุณสามารถออกจากงานนี้เป็นเวลาหลายวัน (ถ้าจำเป็น) การถ่ายโอนข้อมูลข้ามโดยไม่หยุดทำงาน

เมื่อการถ่ายโอนเสร็จสมบูรณ์คุณสามารถปิดกระบวนการ "CheckedAgainstOldData" ที่ช้าได้ และถ่ายโอนข้อมูลทั้งหมดไปยังตารางเดียว

ตรงไปตรงมาหากปัญหาไม่ดีเท่าที่คุณอธิบายและซอฟต์แวร์เก่าแล้วคุณจะมีซ้ำกันหลายพัน


1

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

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