MySQL - Diferencia entre usar count (*) e information_schema.tables para contar filas


16

Quiero una forma rápida de contar el número de filas en mi tabla que tiene varios millones de filas. Encontré la publicación " MySQL: la forma más rápida de contar el número de filas " en Stack Overflow, que parecía resolver mi problema. Bayuah proporcionó esta respuesta:

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

Lo que me gustó porque parece una búsqueda en lugar de un escaneo, por lo que debería ser rápido, pero decidí probarlo

SELECT COUNT(*) FROM table 

para ver cuánta diferencia de rendimiento hubo.

Lamentablemente, obtengo diferentes respuestas como se muestra a continuación:

ingrese la descripción de la imagen aquí

Pregunta

¿Por qué las respuestas son diferentes en aproximadamente 2 millones de filas? Supongo que la consulta que realiza un escaneo completo de la tabla es el número más preciso, pero ¿hay alguna manera de obtener el número correcto sin tener que ejecutar esta consulta lenta?


Corrí ANALYZE TABLE data_302, que completó en 0.05 segundos. Cuando ejecuté la consulta nuevamente, ahora obtengo un resultado mucho más cercano de 34384599 filas, pero todavía no es el mismo número que select count(*)con 34906061 filas. ¿Analiza la devolución de la tabla inmediatamente y procesa en segundo plano? Siento que vale la pena mencionar que esta es una base de datos de prueba y actualmente no se está escribiendo en ella.

A nadie le importará si solo se trata de decirle a alguien qué tan grande es una tabla, pero quería pasar el recuento de filas a un bit de código que usaría esa cifra para crear consultas asincrónicas de "igual tamaño" para consultar la base de datos en paralelo, similar al método que se muestra en Aumento del rendimiento de consultas lentas con la ejecución de consultas paralelas por Alexander Rubin. Tal como está, obtendré la identificación más alta SELECT id from table_name order by id DESC limit 1y espero que mis tablas no se fragmenten demasiado.

Respuestas:


23

Hay varias formas de "contar" filas en una tabla. Lo mejor depende de los requisitos (precisión del recuento, con qué frecuencia se realiza, si necesitamos el recuento de toda la tabla o con variables wherey group bycláusulas, etc.)

  • a) la forma normal. Solo cuéntalas .

    select count(*) as table_rows from table_name ; 

    Precisión : recuento 100% exacto en el momento en que se ejecuta la consulta.
    Eficiencia : No es bueno para mesas grandes. (para las tablas MyISAM es espectacularmente rápido, pero nadie está usando MyISAM en estos días ya que tiene muchas desventajas sobre InnoDB. El "espectacularmente rápido" también se aplica solo al contar las filas de una tabla completa MyISAM, si la consulta tiene una WHEREcondición, todavía tiene que escanear la tabla o un índice.)
    Para las tablas InnoDB, depende del tamaño de la tabla, ya que el motor tiene que escanear la tabla completa o un índice completo para obtener el recuento exacto. Cuanto más grande es la mesa, más lenta se vuelve.

  • b) usando SQL_CALC_FOUND_ROWSy FOUND_ROWS(). Se puede usar en lugar de la forma anterior, si también queremos un pequeño número de filas (cambiando la LIMIT). Lo he visto utilizado para paginación (para obtener algunas filas y al mismo tiempo saber cuántas son int total y calcular el número de pgegs).

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

    Precisión : igual que la anterior.
    Eficiencia : igual que la anterior.

  • c) utilizando las information_schematablas, como la pregunta vinculada:

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

    Precisión : solo una aproximación. Si la tabla es el objetivo de inserciones y eliminaciones frecuentes, el resultado puede estar muy lejos del conteo real. Esto se puede mejorar ejecutando ANALYZE TABLEmás a menudo.
    Eficiencia : Muy bien, no toca la mesa en absoluto.

  • d) almacenar el recuento en la base de datos (en otra tabla "contador" ) y actualizar ese valor cada vez que la tabla tiene una inserción, eliminación o truncamiento (esto se puede lograr con desencadenantes o modificando los procedimientos de inserción y eliminación) .
    Por supuesto, esto pondrá una carga adicional en cada inserción y eliminación, pero proporcionará un recuento preciso.

    Precisión : recuento 100% exacto.
    Eficiencia : Muy bien, necesita leer solo una fila de otra tabla.
    Sin embargo, pone una carga adicional en la base de datos.

  • e) almacenar (almacenar en caché ) el recuento en la capa de aplicación, y usar el primer método (o una combinación de los métodos anteriores). Ejemplo: ejecute la consulta de recuento exacto cada 10 minutos. Mientras tanto, entre dos recuentos, use el valor en caché.

    Precisión : aproximación pero no tan mala en circunstancias normales (a menos que se agreguen o eliminen miles de filas).
    Eficiencia : muy buena, el valor siempre está disponible.


1

Para INNODBque desee information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSpara los datos de recuento preciso fila de la tabla, en lugar de information_schema.TABLES.TABLE_ROWS.

Publiqué más detalles aquí: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843


1
Información incorrecta ... "Para INNODB desea información_esquema.INNODB_SYS_TABLESTATS.NUM_ROWS para una fila de tabla precisa:" el manual dice claramente estimado en la NUM_ROWScolumna
Raymond Nijland
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.