การลดการอ่านที่ทำดัชนีด้วยเกณฑ์ที่ซับซ้อน


12

ฉันกำลังปรับฐานข้อมูลตั๋วทำงาน Firebird 2.5 ให้เหมาะสม พวกมันถูกเก็บไว้ในตารางที่ประกาศเช่นนี้

CREATE TABLE TICKETS (
  TICKET_ID id PRIMARY KEY,
  JOB_ID id,
  ACTION_ID id,
  STATUS str256 DEFAULT 'Pending'
);

โดยทั่วไปฉันต้องการค้นหาตั๋วใบแรกที่ยังไม่ได้ดำเนินการและอยู่ในPendingสถานะ

ลูปการประมวลผลของฉันจะเป็น:

  1. รับตั๋วที่ 1 Pending
  2. ทำงานกับ Ticket
  3. อัปเดตสถานะตั๋ว => Complete
  4. ทำซ้ำ

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

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

- แก้ไขความคิดเห็น -

ใน Firebird คุณจะ จำกัด การดึงข้อมูลแถวเช่น:

Select First 1
  Job_ID, Ticket_Id
From
  Tickets
Where
  Status = 'Pending'

ดังนั้นเมื่อผมบอกว่า "ครั้งแรก" Status = 'Pending'ฉันแค่ขอให้มันมาเป็นชุดบันทึกที่


คุณหมายถึงอะไรกับ"ครั้งแรก"ใน"ดึงตั๋ว 1 ที่ 'รอ'" ?
ypercubeᵀᴹ

ถ้า "แรก" หมายถึงน้อยที่สุดticket_idคุณอาจจำเป็นต้องมีดัชนีในวันที่(status, ticket_id)
ypercubeᵀᴹ

และคุณแน่ใจได้อย่างไรว่าการลดลงของประสิทธิภาพนั้นเกิดจากขั้นตอนนี้และไม่ใช่โดยการสอบถาม / คำสั่งอื่น ๆ
ypercubeᵀᴹ

@ypercube - ไม่ฉันไม่แน่ใจว่าประสิทธิภาพการทำงานลดลง นั่นเป็นสาเหตุที่คำถามของฉันคือ "ฉันต้องเกี่ยวข้องกับเรื่องนี้หรือเป็นพฤติกรรมปกติของดัชนีหรือไม่" เป็นสิ่งที่ฉันสังเกตเห็นขณะตรวจสอบฐานข้อมูลและฉันคิดว่ามันไม่คาดคิด ฉันจะไม่คาดหวังว่ามันจะสแกนแถวก่อนหน้าต่อไปเมื่อฉันระบุข้อที่กับคอลัมน์ที่จัดทำดัชนี FWIW ซึ่งแก้ไขดัชนีเพื่อรวมticket_idการดำเนินการที่แย่กว่าการทำดัชนีสถานะ
gddc

คือid(ชนิดข้อมูล) โดเมนที่คุณกำหนดไว้หรือไม่?
a_horse_with_no_name

คำตอบ:


1

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

ใน SQL Server (และอาจเป็น RDBMS อื่น ๆ ได้) สิ่งนี้สามารถแก้ไขได้โดยใช้ดัชนีที่กรองแล้ว ใน SQL Server คุณจะต้องเพิ่มเงื่อนไข WHERE ลงบนจุดสิ้นสุดของคำนิยามดัชนีของคุณเพื่อพูดว่า "ใช้ดัชนีนี้เฉพาะกับระเบียนที่มีสถานะ <> 'เสร็จสมบูรณ์'" จากนั้นแบบสอบถามใด ๆ ที่ใช้เพรดิเคตนี้จะใช้ดัชนีกับระเบียนจำนวนเล็กน้อยที่ไม่ได้ตั้งค่าเป็น 'เสร็จสมบูรณ์' อย่างไรก็ตามขึ้นอยู่กับเอกสารที่นี่: http://www.firebirdsql.org/refdocs/langrefupd25-ddl-index.htmlดูเหมือนว่า Firebird จะสนับสนุนดัชนีที่กรองแล้ว

วิธีแก้ปัญหาคือการใส่ระเบียน 'เสร็จสมบูรณ์' ในตาราง ArchiveTickets สร้างตารางที่มีคำจำกัดความที่เหมือนกัน (แม้ว่าจะไม่มีรหัสที่สร้างขึ้นอัตโนมัติใด ๆ ) เป็นตาราง Tickets ของคุณและรักษาแถวระหว่างพวกเขาโดยการกด 'เสร็จสมบูรณ์' บันทึกไปยังตาราง ArchiveTickets ดัชนีในตารางบัตรของคุณจะมีจำนวนบันทึกน้อยกว่าและมีประสิทธิภาพสูงกว่ามาก นี่อาจหมายถึงคุณจะต้องเปลี่ยนรายงานอื่น ๆ ที่อ้างอิงตั๋ว 'เสร็จสมบูรณ์' เพื่อชี้ไปที่ตารางเก็บถาวรหรือดำเนินการกับยูเนี่ยนสำหรับทั้งตั๋วและตั๋วถาวร สิ่งนี้จะมีข้อดีของการไม่เพียง แต่รวดเร็ว แต่ยังหมายความว่าคุณสามารถสร้างดัชนีเฉพาะสำหรับตาราง ArchiveTickets เพื่อให้มันทำงานได้ดีขึ้นสำหรับการสืบค้นอื่น ๆ (เช่น:

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


0

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

การสืบค้นที่รอดำเนินการครั้งแรกของคุณนั้นไม่สามารถกำหนดได้ ก่อนตามลำดับอะไร ตาราง SQL ไม่มีคำสั่งที่แท้จริง; First 1สับเป็นเพียงให้คุณบางพลคนแรก เพื่อให้กำหนดขึ้นทำไมไม่ดำเนินการงานที่ค้างอยู่ในลำดับ Job_ID

หากคุณมีสองดัชนี {Job_ID} และ {สถานะ, Job_ID} แบบสอบถามนี้จะส่งคืนหนึ่งแถวที่คาดการณ์และมีประสิทธิภาพ:

Select Job_ID, Ticket_Id
From   Tickets
Where Job_ID = ( 
  select min(Job_ID) from Tickets 
  where Status = 'Pending'
);

ฉันไม่ใช่ผู้ใช้ Firebird ดังนั้นคุณจะต้องตรวจสอบแผนแบบสอบถาม แต่ควรมีประสิทธิภาพเพราะแบบสอบถามย่อยอ้างอิงเฉพาะดัชนีที่สองเท่านั้นที่สร้างมูลค่าให้กับแบบสอบถามแรก (อาจมีเทคนิคอื่น ๆ ที่มีประสิทธิภาพสำหรับคุณคุณอาจจัดระเบียบตารางทางกายภาพเป็นต้นไม้ B + หรือมีการเข้าถึง row_id ที่ซ่อนอยู่เป็นต้น)

การเปลี่ยนแปลงอื่น ๆ ที่ฉันจะทำเพื่อความถูกต้องคือการทำStatusไบต์เดียวแบบ จำกัด และให้แอปพลิเคชันระบุสตริง "รอดำเนินการ" ที่จะป้องกันStatusค่าผิดพลาดและอาจทำให้ดัชนีมีขนาดเล็กลงในการต่อรอง สิ่งที่ต้องการ:

CREATE TABLE TICKETS (
  TICKET_ID id PRIMARY KEY,
  JOB_ID id,
  ACTION_ID id,
  STATUS char(1) not NULL 
     DEFAULT 'P'
     CHECK( STATUS in ('P', 'C', 'X') ) -- whatever the domain is
);

แน่นอนคุณสามารถใช้มุมมอง (หรือคอลัมน์ที่ได้รับ) เพื่อระบุสตริงที่ยอมรับได้สำหรับสถานะ

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