MySQL - ความแตกต่างระหว่างการใช้ count (*) และ information_schema.tables สำหรับการนับแถว


16

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

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

ซึ่งฉันชอบเพราะมันดูเหมือนการค้นหาแทนที่จะสแกนดังนั้นมันควรจะเร็ว แต่ฉันตัดสินใจทดสอบกับมัน

SELECT COUNT(*) FROM table 

เพื่อดูว่ามีความแตกต่างด้านประสิทธิภาพมากน้อยเพียงใด

น่าเสียดายที่ฉันได้รับคำตอบต่าง ๆดังที่แสดงด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

คำถาม

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


ฉันวิ่งANALYZE TABLE data_302ซึ่งเสร็จสมบูรณ์ภายใน 0.05 วินาที เมื่อฉันเรียกใช้แบบสอบถามอีกครั้งตอนนี้ฉันได้รับผลลัพธ์ที่ใกล้เคียงกับ 34384599 แถว แต่ก็ยังไม่เหมือนกันselect count(*)กับ 34906061 แถว วิเคราะห์ตารางที่ส่งคืนทันทีและดำเนินการในพื้นหลังหรือไม่ ฉันรู้สึกว่ามันคุ้มค่าที่จะกล่าวถึงนี่คือฐานข้อมูลทดสอบและไม่ได้ถูกเขียนถึงในขณะนี้

ไม่มีใครสนใจถ้าเป็นเพียงการบอกใครสักคนว่าตารางใหญ่แค่ไหน แต่ฉันต้องการส่งจำนวนแถวไปยังโค้ดที่จะใช้ตัวเลขนั้นเพื่อสร้างคิวรีแบบอะซิงโครนัส "ขนาดเท่ากัน" เพื่อสืบค้นฐานข้อมูล ในแบบคู่ขนานคล้ายกับวิธีการที่แสดงในการเพิ่มประสิทธิภาพการสืบค้นช้าด้วยการดำเนินการแบบสอบถามแบบขนานโดย Alexander Rubin ตามที่เป็นอยู่ฉันจะได้รับไอดีสูงสุดด้วยSELECT id from table_name order by id DESC limit 1และหวังว่าตารางของฉันจะไม่แยกส่วนเกินไป

คำตอบ:


23

มีหลายวิธีในการ "นับ" แถวในตาราง สิ่งที่ดีที่สุดขึ้นอยู่กับข้อกำหนด (ความถูกต้องของการนับความถี่ดำเนินการไม่ว่าเราจะต้องนับทั้งตารางหรือตัวแปรwhereและส่วนgroup byคำสั่ง ฯลฯ )

  • a)วิธีปกติ เพียงแค่นับพวกเขา

    select count(*) as table_rows from table_name ; 

    ความแม่นยำ : การนับที่แม่นยำ 100% ณ เวลาที่ทำการสืบค้น
    ประสิทธิภาพ : ไม่ดีสำหรับโต๊ะขนาดใหญ่ (สำหรับตาราง MyISAM นั้นรวดเร็วและน่าตื่นเต้น แต่ก็ไม่มีใครใช้ MyISAM ในวันนี้เนื่องจากมีข้อเสียมากมายกับ InnoDB การ"รวดเร็วอย่างน่าทึ่ง" จะมีผลก็ต่อเมื่อการนับแถวของตาราง MyISAM ทั้งหมด - หากแบบสอบถามมีWHEREเงื่อนไข ยังคงต้องสแกนตารางหรือดัชนี)
    สำหรับตาราง InnoDB นั้นขึ้นอยู่กับขนาดของตารางเนื่องจากเอนจินต้องทำการสแกนทั้งตารางหรือดัชนีทั้งหมดเพื่อให้ได้จำนวนที่แม่นยำ ยิ่งตารางยิ่งใหญ่ก็ยิ่งช้าลง

  • ข)การใช้และSQL_CALC_FOUND_ROWS FOUND_ROWS()สามารถใช้แทนวิธีก่อนหน้าได้ถ้าเราต้องการแถวจำนวนน้อยเช่นกัน (เปลี่ยนLIMIT) ฉันเคยเห็นมันใช้สำหรับการเพจ (เพื่อให้ได้แถวและในเวลาเดียวกันรู้ว่ามีจำนวนรวมทั้งหมดและคำนวณจำนวน pgegs)

    select sql_calc_found_rows * from table_name limit 0 ; 
    select found_rows() as table_rows ;

    ความแม่นยำ : เหมือนกับก่อนหน้านี้
    ประสิทธิภาพ : เหมือนกับก่อนหน้านี้

  • c)ใช้information_schemaตารางเป็นคำถามที่เชื่อมโยง:

    select  table_rows
    from    information_schema.tables
    where   table_schema = 'database_name'
      and   table_name = 'table_name' ;

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

  • d)จัดเก็บการนับในฐานข้อมูล (ในอีกตาราง "ตัวนับ" ) และอัปเดตค่านั้นทุกครั้งที่ตารางมีการแทรกลบหรือตัด (ซึ่งสามารถทำได้ด้วยทริกเกอร์หรือโดยการปรับเปลี่ยนการแทรกและลบ) .
    ซึ่งแน่นอนว่าจะเพิ่มการโหลดในแต่ละส่วนแทรกและลบ แต่จะให้การนับที่แม่นยำ

    ความแม่นยำ : การนับที่แม่นยำ 100%
    ประสิทธิภาพ : ดีมากต้องการอ่านเพียงแถวเดียวจากตารางอื่น
    มันทำให้การโหลดเพิ่มเติมไปยังฐานข้อมูล

  • e) การจัดเก็บ ( แคช ) การนับในเลเยอร์แอปพลิเคชัน - และใช้วิธีที่ 1 (หรือการรวมกันของวิธีการก่อนหน้านี้) ตัวอย่าง: เรียกใช้แบบสอบถามจำนวนนับทุก 10 นาที ในช่วงเวลาเฉลี่ยระหว่างการนับสองครั้งให้ใช้ค่าแคช

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


1

สำหรับINNODBคุณต้องการสำหรับตารางที่ถูกต้องข้อมูลจำนวนแถวแทนinformation_schema.INNODB_SYS_TABLESTATS.NUM_ROWSinformation_schema.TABLES.TABLE_ROWS

ฉันโพสต์รายละเอียดเพิ่มเติมได้ที่นี่: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843


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