MySQL - різниця між використанням count (*) та information_schema.tables для підрахунку рядків


16

Я хочу швидким способом підрахувати кількість рядків у моїй таблиці, яка містить кілька мільйонів рядків. Я знайшов пост " MySQL: найшвидший спосіб підрахунку кількості рядків " на стеку Overflow, який, схоже, вирішив мою проблему. Баюа дав цю відповідь:

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 рядків. Чи аналізує таблицю аналізу негайно та обробляє у фоновому режимі? Я вважаю, що варто згадати, що це тестова база даних, і вона наразі не пишеться.

Нікого не буде байдуже, якщо це просто випадок сказати комусь, наскільки велика таблиця, але я хотів передати кількість рядків до трохи коду, який використовував би цю фігуру для створення асинхронних запитів "однакового розміру" для запиту бази даних паралельно, аналогічно методу, показаному в Підвищенні повільної продуктивності запиту при виконанні паралельного запиту Олександром Рубіним. Як це є, я просто отримаю найвищий ідентифікатор SELECT id from table_name order by id DESC limit 1і сподіваюся, що мої таблиці не надто роздроблені.

Відповіді:


23

Існують різні способи "підрахунку" рядків у таблиці. Що найкраще залежить від вимог (точність підрахунку, як часто виконується, чи потрібна нам підрахунок всієї таблиці або зі змінною whereта group byпропозиціями тощо)

  • а) нормальним способом. Просто порахуйте їх.

    select count(*) as table_rows from table_name ; 

    Точність : 100% точне підрахунок під час запуску запиту.
    Ефективність : Не підходить для великих столів. (для таблиць MyISAM надзвичайно швидко, але ніхто не використовує MyISAM в наші дні, оскільки у нього стільки недоліків у порівнянні з InnoDB. "Ефектно швидкий" також застосовується лише під час підрахунку рядків цілої таблиці MyISAM - якщо запит має WHEREумову, він все ще доводиться сканувати таблицю або індекс.)
    Для таблиць InnoDB це залежить від розміру таблиці, оскільки двигун повинен виконати сканування цілої таблиці або цілого індексу, щоб отримати точний підрахунок. Чим більший стіл, тим повільніше він стає.

  • б) використання SQL_CALC_FOUND_ROWSі FOUND_ROWS(). Можна використовувати замість попереднього способу, якщо ми також хочемо невелику кількість рядків (змінивши LIMIT). Я бачив, як він використовується для пейджингу (щоб отримати кілька рядків і в той же час знати, скільки всього int і обчислити кількість піггів).

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

    Точність : така ж, як і попередня.
    ККД : такий же, як і попередній.

  • в) використання information_schemaтаблиць як пов'язаного питання:

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

    Точність : Лише наближення. Якщо таблиця є частою вставкою та видаленням, результат може бути відхилений від фактичного підрахунку. Це можна покращити, ANALYZE TABLEчастіше бігаючи .
    Ефективність : Дуже добре, він зовсім не торкається столу.

  • г) зберігання підрахунку в базі даних (в іншій таблиці «лічильник» ) та оновлення цього значення кожного разу, коли в таблиці є вставка, видалення або скорочення (це можна досягти або за допомогою тригерів, або шляхом зміни процедур вставки та видалення) .
    Це, звичайно, додасть додаткове навантаження в кожну вставку та видалення, але забезпечить точний підрахунок.

    Точність : 100% точний підрахунок.
    Ефективність : Дуже добре, потрібно читати лише один рядок з іншої таблиці.
    Однак це додатково завантажує базу даних.

  • д) зберігання ( кешування ) рахунку в шарі програми - та з використанням 1-го методу (або комбінації попередніх методів). Приклад: запускайте запит точного підрахунку кожні 10 хвилин. У середній час між двома підрахунками використовуйте кешоване значення.

    Точність : наближення, але не надто погано в звичайних обставинах (якщо не додано або видалено тисячі рядків).
    Ефективність : Дуже добре, значення завжди доступне.


1

Тому що INNODBви хочете information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSотримати точні дані про кількість таблиць, замість них information_schema.TABLES.TABLE_ROWS.

Більше деталей я опублікував тут: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843


1
Неправильна інформація ... "Для INNODB ви хочете отримати інформацію_schema.INNODB_SYS_TABLESTATS.NUM_ROWS для точного рядка таблиці:" керівництво чітко говорить про оцінку на NUM_ROWSколонці
Raymond Nijland
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.