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

16

Я хочу быстрый способ подсчитать количество строк в моей таблице, которая имеет несколько миллионов строк. Я обнаружил сообщение « MySQL: самый быстрый способ подсчета количества строк » в переполнении стека, которое выглядело так, как будто это решило бы мою проблему. 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 строк. Анализирует ли таблица сразу и обрабатывает ли он в фоновом режиме? Я чувствую, что стоит упомянуть, что это тестовая база данных, и в настоящее время она не пишется.

Никого не волнует, если это просто случай, когда кто-то говорит, насколько велика таблица, но я хотел передать количество строк в фрагмент кода, который будет использовать эту цифру для создания асинхронных запросов одинакового размера для запросов к базе данных. параллельно, аналогично методу, показанному в статье «Повышение производительности медленных запросов при параллельном выполнении запросов » Александром Рубиным. На самом деле, я просто получу самый высокий идентификатор SELECT id from table_name order by id DESC limit 1и надеюсь, что мои таблицы не будут слишком фрагментированными.

Programster
источник

Ответы:

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чаще.
    Эффективность : очень хорошо, это совсем не касается стола.

  • d) сохранить счет в базе данных (в другой таблице «counter» ) и обновлять это значение каждый раз, когда в таблицу вставляются, удаляются или усекаются (это может быть достигнуто либо с помощью триггеров, либо путем изменения процедур вставки и удаления) ,
    Это, конечно, добавит дополнительную нагрузку в каждую вставку и удаление, но обеспечит точный подсчет.

    Точность : 100% точный счет.
    Эффективность : очень хорошо, нужно прочитать только одну строку из другой таблицы.
    Это добавляет дополнительную нагрузку на базу данных.

  • e) сохранение ( кэширование ) счетчика на прикладном уровне - и использование 1-го метода (или комбинации предыдущих методов). Пример: запускать запрос точного количества каждые 10 минут. В промежутке между двумя счетами используйте кэшированное значение.

    Точность : приблизительная, но не слишком плохая в обычных условиях (кроме случаев, когда тысячи строк добавляются или удаляются).
    Эффективность : очень хорошо, ценность всегда доступна.

ypercubeᵀᴹ
источник
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 вы хотите, чтобы information_schema.INNODB_SYS_TABLESTATS.NUM_ROWS для точной строки таблицы:" в руководстве четко сказано, оценивается ли в NUM_ROWSстолбце
Рэймонд