การจัดทำดัชนี MySQL VarChar


10

ฉันกำลังพยายามจัดทำดัชนีblogentriesฐานข้อมูลของฉันเพื่อประสิทธิภาพที่ดีขึ้น แต่พบปัญหา

นี่คือโครงสร้าง:

CREATE TABLE IF NOT EXISTS `blogentries` (
  `id_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
  `entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
  `date_id` int(11) NOT NULL,
  PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;

แบบสอบถามแบบนี้ใช้ดัชนีอย่างถูกต้อง:

EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + + ------------- ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| id | select_type | ตาราง | ประเภท | possible_keys | กุญแจ key_len | ref | แถว | พิเศษ |
+ ---- + + ------------- ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
| 1 | ง่าย ๆ บล็อก ดัชนี | NULL | หลัก | 114 | NULL | 126 | ใช้ดัชนี |
+ ---- + + ------------- ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +

อย่างไรก็ตามเมื่อฉันเพิ่มentry_idเข้าไปในSELECTแบบสอบถามมันใช้ filesort

EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + + ------------- ------------- + ------ + --------- ------ ------ + + --------- + ------ + ------ + ------------ ---- +
| id | select_type | ตาราง | ประเภท | possible_keys | กุญแจ key_len | ref | แถว | พิเศษ |
+ ---- + + ------------- ------------- + ------ + --------- ------ ------ + + --------- + ------ + ------ + ------------ ---- +
| 1 | ง่าย ๆ บล็อก ทั้งหมด | NULL | NULL | NULL | NULL | 126 | การใช้ filesort |
+ ---- + + ------------- ------------- + ------ + --------- ------ ------ + + --------- + ------ + ------ + ------------ ---- +

ฉันสงสัยว่าทำไมสิ่งนี้จึงเกิดขึ้นและฉันจะหลีกเลี่ยงได้อย่างไร มันเกิดจากการVarCharและสิ่งที่ควรจะเปลี่ยนเป็นอย่างอื่น?

ฉันพยายามที่จะทำให้ข้อความค้นหาทั้งหมดของฉันใช้ดัชนีขณะที่ฉันกำลังใช้งานสูงHandler_read_rndและมีHandler_read_rnd_nextค่า

หากคุณต้องการข้อมูลอื่น ๆ ฉันสามารถโพสต์ได้เช่นกัน


filesort หมายความว่าทำงานเรียงลำดับบนดิสก์
มิตมิต

ลองเพิ่มWHERE 1=1ในแบบสอบถามที่สองของคุณ
มิตมิต

MySQL รุ่นนี้คืออะไร? ขนาดบัฟเฟอร์การจัดเรียงของคุณคืออะไร ( SELECT @@sort_buffer_size)?

@njk filesort เป็นผลมาจากส่วนของ 'ORDER BY' ของแบบสอบถาม

1
@TashPemhiwa ไม่จำเป็นต้องดูคำสั่งแรก
มิตมิต

คำตอบ:


6

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


แน่นอนว่า MySQL ควรใช้ดัชนีสำหรับORDER BY?
eggyal

@eggyal ไม่ใช่ถ้ามันใหญ่เกินไปสำหรับหน่วยความจำ
มิตมิต

@njk: มันไม่สมเหตุสมผล ... มันสามารถสำรวจดัชนีตามลำดับโดยไม่จำเป็นต้องโหลดสิ่งทั้งหมดลงในหน่วยความจำ ผลลัพธ์จะถูกจัดเรียงโดยไม่จำเป็นต้องทำการเรียงไฟล์
eggyal

@eggyal varchar(5000)ฉันจะถามขนาดของ
มิตมิต

@njk: แต่คอลัมน์นั้นไม่ได้อยู่ในดัชนีหรือถูกใช้ในการเรียงลำดับ
eggyal

2

ตามเอกสารภายใต้ORDER BYการปรับให้เหมาะสม :

สำหรับการค้นหาช้าที่filesortไม่ได้ใช้ลองลดค่าที่เหมาะสมกับทริกเกอร์ที่max_length_for_sort_datafilesort

ในบทความบล็อกของเขาคืออะไร read_rnd_buffer_size อะไร Peter Zaitsev อธิบาย:

สำหรับฉันนี่หมายถึงเนื่องจาก MySQL 4.1 ตัวเลือกนี้จะใช้ในช่วงแคบ ๆ ของกรณี - ถ้าคุณดึงข้อมูลบางฟิลด์ (น้อยกว่าmax_length_for_sort_data ) ข้อมูลควรเก็บไว้ใน sort buffer และเรียงไฟล์ดังนั้นจะไม่จำเป็นต้อง read_rnd_buffer ถ้าคอลัมน์ที่เลือก มีความยาวดังนั้นจึงมีความยาวมากกว่าmax_length_for_sort_data ซึ่งบ่อยครั้งก็หมายความว่ามีคอลัมน์ TEXT / BLOB อยู่บ้าง มันจะถูกใช้อย่างไรก็ตามถ้ามีคอลัมน์จำนวนมากหรือมีคอลัมน์ VARCHAR ยาวที่ใช้ - ใช้ UTF8 VARCHAR เพียง 255 คู่ในการสร้างแถวที่ยาวกว่าmax_length_for_sort_dataในการนำเสนอแบบคงที่

นี่เป็นการชี้ให้เห็นว่าmax_length_for_sort_dataมีการ จำกัด ขนาดรวมของคอลัมน์ที่มีการเลือกข้างต้นซึ่งfilesortจะใช้แทนการเรียงลำดับตามดัชนี

ในกรณีของคุณการเลือกentry_id(5002 ไบต์) จะใช้ขนาดโดยรวมมากกว่าค่าเริ่มต้น 1KiB ของตัวแปรนี้ดังนั้นจึงfilesortใช้ หากต้องการเพิ่มขีด จำกัด เป็น 8KiB คุณสามารถทำได้:

SET SESSION max_length_for_sort_data = 8192;

ฉันมีตารางที่มีการตั้งค่าคล้ายกันมากกับการตั้งค่านี้และการตั้งค่านี้ไม่ปรากฏขึ้นเพื่อกระตุ้นการเปลี่ยนแปลงใด ๆ ในการใช้งานชุดไฟล์

@uffinista: น่าสนใจ ฉันคิดว่ามันอาจเกี่ยวข้องกับการตั้งค่าบัฟเฟอร์อื่น ๆ ต่อคำตอบของ @ RolandoMySQLDBA ?
eggyal

2

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

ดูเพิ่มเติม: 10 เคล็ดลับสำหรับการเพิ่มประสิทธิภาพ MySQL แบบสอบถาม (ที่ไม่ดูด)

ดังนั้นหากเป็นไปได้ที่จะมีดัชนีใน entry_id คุณสามารถเพิ่มและตั้งค่าทั้งหมดได้ แต่ฉันสงสัยว่ามันเป็นตัวเลือกดังนั้นจะทำอย่างไร?

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

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

ต่อไปนี้เป็นคำตอบอื่น ๆ ของ SO ที่พูดถึงคำถามนี้:


ข้อความค้นหาแรกของ OP " มีข้อมูลความยาวผันแปรใน MySQL และไม่มีดัชนีที่ตรงกับคอลัมน์ทั้งหมดที่ร้องขอ " แต่filesortก็ไม่ได้ใช้ในกรณีนี้ ฉันยังคิดว่าแม้การเรียงลำดับตารางเล็ก ๆ ในหน่วยความจำเพียงอย่างเดียวก็สามารถพิสูจน์ได้ว่าเป็นประสิทธิภาพที่ไม่อาจยอมรับได้เช่นหากมีการดำเนินการสืบค้นจำนวนมาก (และตารางจะเปลี่ยนเพื่อไม่ให้แคชใช้)
eggyal

ฉันไม่มีเวลาในการทดสอบ แต่ฉันสงสัยว่านี่จะถูกเรียกใช้โดยมี VARCHAR ซึ่งต้องใช้ 2 ไบต์สำหรับการจัดเก็บความยาวตามที่ระบุในdev.mysql.com/doc/refman/5.1/en/char html - ดังนั้นเคียวรีแรกที่พอดีภายในขีด จำกัด นั้น แต่เคียวรีที่สองไม่ได้

0

ลองเพิ่มWHEREประโยคในแบบสอบถามของคุณ

ดัชนีสามารถใช้งานได้ถ้าORDER BYไม่ตรงกับดัชนีว่าตราบใดที่ทุกส่วนที่ไม่ได้ใช้ของดัชนีและทุกพิเศษORDER BYคอลัมน์ค่าคงที่ในWHEREข้อ ในบางกรณี, MySQL ไม่สามารถใช้ดัชนีการแก้ไขORDER BYแม้ว่ามันจะยังคงใช้ดัชนีการค้นหาแถวที่ตรงกับWHEREข้อ

http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html


แต่ในกรณีนี้การจับคู่ดัชนีORDER BY ไม่ตรงกันดังนั้นจึงไม่จำเป็นต้องมีWHEREประโยค
eggyal

ฉันมีคำสั่ง "ที่" ในแบบสอบถามจริงในเว็บไซต์ดังนั้นฉันรู้ว่าไม่ใช่สาเหตุของการจัดเรียงไฟล์ ฉันสงสัยว่ามันใช้ varchar หรือไม่?

0

ตามความรู้ของฉัน varchar สามารถเก็บได้สูงสุด 8000 ไบต์ซึ่งมีความยาวประมาณ 4000 อักขระ ดังนั้นดูเหมือนว่า 5,000 คนจะเกินขีด จำกัด ของที่เก็บข้อมูลและในกรณีนี้อาจเป็นสาเหตุที่ทำให้การเรียงลำดับยุ่งเหยิง

"varchar [(n | สูงสุด)] ข้อมูลอักขระที่มีความยาวผันแปรและไม่ใช่ Unicode สามารถเป็นค่าได้ตั้งแต่ 1 ถึง 8,000 max ระบุว่าขนาดพื้นที่เก็บข้อมูลสูงสุดคือ 2 ^ 31-1 ไบต์ขนาดของหน่วยเก็บเป็นจริง ความยาวของข้อมูลที่ป้อน + 2 ไบต์ข้อมูลที่ป้อนอาจมีความยาว 0 อักขระคำพ้องความหมาย SQL-2003 สำหรับ varchar มีลักษณะที่แตกต่างกันหรืออักขระต่างกัน "

หวังว่านี่จะตอบคำถามของคุณ


ดังที่บันทึกไว้ภายใต้The CHARand VARCHARTypes : " Values ​​ในคอลัมน์ VARCHAR เป็นสตริงที่มีความยาวผันแปรได้สามารถระบุความยาวเป็นค่าตั้งแต่ 0 ถึง 255 ก่อน MySQL 5.0.3 และ 0 ถึง 65,535 ใน 5.0.3 และรุ่นที่ใหม่กว่า ความยาวสูงสุดของ a VARCHARใน MySQL 5.0.3 และใหม่กว่านั้นขึ้นอยู่กับขนาดแถวสูงสุด (65,535 ไบต์ซึ่งใช้ร่วมกันในทุกคอลัมน์) และชุดอักขระที่ใช้ "
eggyal

0

คุณมีเพียง 126 แถวในตารางของคุณ แม้ว่าทุกแถวจะมีขนาดสูงสุดถึงประมาณ 5KB นั่นก็หมายความว่าขนาดทั้งหมดที่อ่านจากดิสก์นั้นมีขนาดเพียงประมาณ 600KB ซึ่งไม่มากเลย หากพูดอย่างตรงไปตรงมามันมีปริมาณน้อยมากอาจน้อยกว่าขนาดแคชของดิสก์ไดรฟ์ที่ทันสมัยที่สุด

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

ในกรณีของคุณจะมีประสิทธิภาพมากกว่าในการอ่านข้อมูลทั้งตารางจากดิสก์เป็นบล็อกเดียวไปยังหน่วยความจำ (อาจเป็นเพียงการอ่านหรือค้นหาดิสก์) จากนั้นเรียงลำดับใน RAM เพื่อตอบสนอง ORDER BY ซึ่งทันทีเมื่อเทียบกับดิสก์ การดำเนินการอ่าน หากเซิร์ฟเวอร์อ่านข้อมูลของคุณตามดัชนีมันจะต้องมีการดำเนินการอ่านมากถึง 126 (อุ๊ปส์!) โดยการค้นหาไปมาภายในไฟล์ข้อมูลเดียวกันหลายครั้ง

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

และสาเหตุที่ทำให้ WAS ใช้ดัชนีเมื่อไม่รวมเขตข้อมูล 5KB เป็นเพราะข้อมูลที่ดึงมานั้นไม่ถือเป็น 99% ของข้อมูลในตาราง เมื่อคุณรวมเขตข้อมูล 5KB ของคุณตอนนี้แบบสอบถามจะต้องอ่าน 99% ของข้อมูลและมีราคาถูกกว่าในการอ่านข้อมูลทั้งหมดและเรียงลำดับในหน่วยความจำหลังจากนั้น


ดูเหมือนว่าคุณกำลังยุ่งเหยิงหลายสิ่งจากวิธีการหลีกเลี่ยงการสแกนเต็มตารางซึ่งจะทำอย่างไรกับการใช้ดัชนีในJOINเงื่อนไขที่น่าพอใจและส่วนWHEREคำสั่งไม่ใช่ORDER BYข้อ
eggyal

ตรงกันข้าม ในกรณีนี้การสแกนตารางแบบเต็มเป็นสิ่งที่ดีเพียงเพราะว่ามันเร็วกว่าการอ่านตามลำดับดัชนี

0

คุณใช้ MySQL รุ่นใด

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

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