Qcache_free_memory ยังไม่เต็ม แต่ฉันได้รับ Qcache_lowmem_prunes จำนวนมาก


11

ฉันเพิ่งเริ่มเล่นน้ำกับแคชแบบสอบถามสำหรับ CMS ของเรา

ทุกคนสามารถบอก (หรืออย่างน้อยให้เดาดี) เหตุผลที่ผมได้รับเป็นจำนวนมากของQcache_lowmem_prunesเมื่อมากกว่าครึ่งหนึ่งของQcache_free_memoryฟรี?

query_cache_size=512M
query_cache_limit=1M

นี่คือลักษณะที่จะดูแลประมาณ 12 ชั่วโมง

show status like '%qcach%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 10338     | 
| Qcache_free_memory      | 297348320 | 
| Qcache_hits             | 10254104  | 
| Qcache_inserts          | 6072945   | 
| Qcache_lowmem_prunes    | 725279    | 
| Qcache_not_cached       | 2237603   | 
| Qcache_queries_in_cache | 48119     | 
| Qcache_total_blocks     | 111346    | 
+-------------------------+-----------+

นี่คือวิธีการที่จะมองตามหลังflush query cache;

show status like '%qcach%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 1         | 
| Qcache_free_memory      | 443559256 | 
| Qcache_hits             | 10307015  | 
| Qcache_inserts          | 6115890   | 
| Qcache_lowmem_prunes    | 725279    | 
| Qcache_not_cached       | 2249405   | 
| Qcache_queries_in_cache | 26455     | 
| Qcache_total_blocks     | 54490     | 
+-------------------------+-----------+

คำตอบ:


21

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

แคชคิวรีเริ่มต้นจากการเป็นหนึ่งหน่วยความจำที่มีขนาดใหญ่ต่อเนื่องกัน จากนั้น "บล็อก" ถูกแกะสลักจากบล็อกขนาดใหญ่นี้:

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

ขนาดบล็อกเป็นแบบไดนามิก แต่เซิร์ฟเวอร์จะจัดสรรอย่างน้อยquery_cache_min_res_unitไบต์ต่อบล็อกโดยมีค่าเริ่มต้นโดยทั่วไปคือ 4096 ไบต์

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

แน่นอนบล็อกฟรีขนาดเล็กกว่าquery_cache_min_res_unitจะไม่ถูกใช้เลย

ดังนั้นเคียวรีแคชแฟรกเมนต์ ถ้าเซิร์ฟเวอร์ที่ต้องการแคชแบบสอบถามใหม่และไม่มีการบล็อกฟรีมีขนาดเพียงพอสามารถจัด (นั่นคือคำอธิบายง่าย deceptively เพราะขั้นตอนวิธีพื้นฐานที่มีความซับซ้อน) อย่างอื่นจะต้องมีการตัดแต่ง ... Qcache_lowmem_prunesที่ของคุณ มีอัลกอริทึม "น้อยที่สุดเมื่อเร็ว ๆ นี้" (LRU) ที่ใช้ตัดสินใจสิ่งที่ถูกตัด

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

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

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

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

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

นี่เป็นเพราะในบางวิธีแคชแบบสอบถามนั้นยอดเยี่ยมในความเรียบง่าย

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

นอกจากนี้แคชแบบสอบถามจะถูกตรวจสอบสำหรับคิวรีขาเข้าแต่ละรายการก่อนที่เซิร์ฟเวอร์จะแยกวิเคราะห์คิวรีจริง สิ่งเดียวที่จะจับคู่คือแบบสอบถามอื่นที่แม่นยำเหมือนกันไบต์ต่อไบต์ SELECT * FROM my_tableและselect * from my_tableไม่เหมือนกันไบต์ต่อไบต์ดังนั้นแคชแบบสอบถามไม่ทราบว่าเป็นคิวรี่เดียวกัน

FLUSH QUERY CACHEไม่ล้างแคชแบบสอบถาม มันจัดระเบียบแคชแบบสอบถามซึ่งเป็นสาเหตุที่Qcache_free_blocksกลายเป็น "1" พื้นที่ว่างทั้งหมดถูกรวมเข้าด้วยกัน

RESET QUERY CACHE จริง ๆ แล้วจะล้างออก (ล้างเนื้อหาทั้งหมดของ) แคชแบบสอบถาม

FLUSH STATUSล้างนับ SHOW STATUSแต่นี้เป็นสิ่งที่คุณไม่ต้องการที่จะทำประจำเพราะเลขนี้ออกมามากที่สุดของตัวแปรสถานะ

นี่คือการสาธิตอย่างรวดเร็ว

พื้นฐาน:

mysql> show status like '%qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67091120 |
| Qcache_hits             | 0        |
| Qcache_inserts          | 0        |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 1        |
| Qcache_queries_in_cache | 0        |
| Qcache_total_blocks     | 1        |
+-------------------------+----------+

เรียกใช้แบบสอบถาม ...

mysql> select * from junk where id = 2;

บล็อกทั้งหมดเพิ่มขึ้น 3 แทรกโดย 1 และแบบสอบถามในแคชคือ 1

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67089584 |
| Qcache_inserts          | 1        |
| Qcache_queries_in_cache | 1        |
| Qcache_total_blocks     | 4        |
+-------------------------+----------+

เรียกใช้ข้อความค้นหาเดียวกัน แต่ใช้ตัวพิมพ์ใหญ่ต่างกัน ...

mysql> SELECT * FROM junk where id = 2;

แบบสอบถามนี้ถูกแคชแยกจากกัน บล็อกทั้งหมดเพิ่มขึ้นเพียง 2 เพราะเรามีบล็อกที่จัดสรรไว้สำหรับตารางแล้ว

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67088560 |
| Qcache_inserts          | 2        |
| Qcache_queries_in_cache | 2        |
| Qcache_total_blocks     | 6        |
+-------------------------+----------+

ตอนนี้เราเปลี่ยนที่แตกต่างกันแถวในตาราง

mysql> update junk set things = 'items' where id = 1;

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

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 1        |
| Qcache_free_memory      | 67091120 |
| Qcache_queries_in_cache | 0        |
| Qcache_total_blocks     | 1        |
+-------------------------+----------+

MySQL จะไม่เก็บแบบสอบถามไว้ในแคชที่ไม่ได้กำหนดไว้เช่นSELECT NOW();หรือแบบสอบถามใด ๆ ที่คุณบอกว่าไม่ให้แคชโดยเฉพาะ SELECT SQL_NO_CACHE ...เป็นคำสั่งที่บอกเซิร์ฟเวอร์ไม่ให้เก็บผลลัพธ์ไว้ในแคช มันมีประโยชน์สำหรับการเปรียบเทียบเวลาดำเนินการจริงของคิวรีเมื่อแคชให้การตอบสนองที่รวดเร็วในการดำเนินการที่ตามมา


ในตัวอย่างของคุณถูกต้องหรือไม่ว่า query_cache_min_res_unit = 512 หน่วยความจำอิสระลดลง 512 * 3 ระหว่างบล็อกที่ใช้ 1 ถึง 4 และ 512 * 2 ระหว่างบล็อกที่ใช้ 4 และ 6
aland

1
@ ที่ดินที่เป็นจุดที่ดีมาก ไม่ฉันควรใช้ค่าเริ่มต้นที่ 4096 แล้วดูเหมือนว่าคิวรีแคชจะตัดขอบบล็อกให้เหลือพลังงานน้อยที่สุดที่เป็นไปได้ของสองหลังจากกรอกแล้วปล่อยให้มีพื้นที่ว่างในตอนท้ายเพื่อให้ 7 / 8th ของ 4096 ไบต์ทั้งหมดที่จัดสรรไว้ในตอนแรกยังไม่ได้ถูกควั่น ฉันจะต้องขุดลึกลงไปในนี้
Michael - sqlbot
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.