Todo el mundo sabe que, en las tablas que usan InnoDB como motor, las consultas como SELECT COUNT(*) FROM mytable
son muy inexactas y muy lentas, especialmente cuando la tabla se hace más grande y hay inserciones / eliminaciones de filas constantes mientras se ejecuta esa consulta.
Como lo entendí, InnoDB no almacena el recuento de filas en una variable interna, que es la razón de este problema.
Mi pregunta es: ¿por qué es así? ¿Sería tan difícil almacenar esa información? Es una información importante para saber en tantas situaciones. La única dificultad que veo si tal recuento interno se implementaría es cuando se trata de transacciones: si la transacción no se confirma, ¿cuenta las filas insertadas por ella o no?
PD: No soy un experto en bases de datos, solo soy alguien que tiene MySQL como un simple pasatiempo. Entonces, si acabo de preguntar algo estúpido, no seas excesivamente crítico: D.
SELECT COUNT(*) FROM ...
consultas reales son precisas. Si lo prefiere, phpMyAdmin se puede configurar para usar siempre recuentos de filas exactos a expensas de la velocidad. Más información: stackoverflow.com/questions/11926259/…Respuestas:
Estoy de acuerdo con @RemusRusanu (+1 por su respuesta)
SELECT COUNT(*) FROM mydb.mytable
en InnoDB se comporta como debería hacerlo un motor de almacenamiento transaccional. Compárelo con MyISAM.MyISAM
Si
mydb.mytable
es una tabla MyISAM, el lanzamientoSELECT COUNT(*) FROM mydb.mytable;
es como ejecutarSELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';
. Esto desencadena una búsqueda rápida del recuento de filas en el encabezado de la tabla MyISAM.InnoDB
Si se
mydb.mytable
trata de una tabla InnoDB, obtienes un montón de cosas que suceden. Tienes MVCC en marcha, que rige lo siguiente:Pedirle a InnoDB un recuento de tablas requiere navegar a través de estas cosas siniestras. De hecho, uno nunca sabe si solo
SELECT COUNT(*) from mydb.mytable
cuenta las lecturas repetibles o si incluye las lecturas que se han confirmado y las que no se han confirmado.Puede intentar estabilizar un poco las cosas habilitando innodb_stats_on_metadata .
De acuerdo con la documentación de MySQL en innodb_stats_on_meta_data
Deshabilitarlo puede o no darle un conteo más estable en términos de configurar planes EXPLAIN. Puede afectar el rendimiento de
SELECT COUNT(*) from mydb.mytable
una manera buena, mala o de ninguna manera. Pruébalo y verás !!!fuente
Para empezar, no existe el 'conteo actual' para almacenar en una variable. Una consulta como
SELECT COUNT(*) FROM ...
está sujeta al nivel de aislamiento actual y a todas las transacciones pendientes concurrentes. Dependiendo del nivel de aislamiento, la consulta puede ver o no ver filas insertadas o eliminadas por transacciones pendientes no confirmadas. La única forma de responder es contar las filas que son visibles para la transacción actual.Tenga en cuenta que ni siquiera toqué el tema aún más espinoso de las transacciones concurrentes que comienzan o terminan durante el conteo. Sin mencionar los retrocesos ...
fuente
COUNT(*)
consultas rara vez se necesitan en la realidad y, por lo general, son el resultado de la inexperiencia del desarrollador (¡cuente las filas antes de seleccionarlas!) O del mal diseño de la aplicación.SELECT COUNT(*)
, agregue una no optimizadaWHERE
a la tabla y tendrá unos pocos usuarios poniendo el db de rodillas para varios contadores de estadísticas cuestionablemente útiles.Si bien en teoría sería posible mantener un recuento preciso del número de filas para una tabla dada con InnoDB, sería a costa de muchos bloqueos, lo que afectaría negativamente el rendimiento. También diferiría según el nivel de aislamiento.
MyISAM ya realiza el bloqueo a nivel de tabla, por lo que no hay costo adicional allí.
Raramente necesito un recuento de filas para una tabla, aunque sí uso COUNT (*) bastante. Generalmente tengo una cláusula WHERE adjunta. Usando un índice eficiente en un pequeño conjunto de resultados, encuentro que son lo suficientemente rápidos.
No estoy de acuerdo con que los recuentos sean inexactos. Los recuentos representan una instantánea de los datos, y siempre los he encontrado exactos.
En resumen, MySQL le deja a usted implementar esto para InnoDB. Puede almacenar un recuento e incrementarlo / disminuirlo después de cada consulta. Sin embargo, la solución más fácil es probablemente cambiar a MyISAM.
fuente