Necesito saber el número de filas en una tabla para calcular un porcentaje. Si el recuento total es mayor que alguna constante predefinida, usaré el valor constante. De lo contrario, usaré el número real de filas.
Puedo usar SELECT count(*) FROM table
. Pero si mi valor constante es 500,000 y tengo 5,000,000,000 filas en mi tabla, contar todas las filas desperdiciará mucho tiempo.
¿Es posible dejar de contar tan pronto como se supere mi valor constante?
Solo necesito el número exacto de filas siempre que esté por debajo del límite dado. De lo contrario, si el recuento está por encima del límite, utilizo el valor límite y quiero la respuesta lo más rápido posible.
Algo como esto:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
sql
postgresql
count
row
Renato Dinhani
fuente
fuente
Respuestas:
Se sabe que el recuento de filas en tablas grandes es lento en PostgreSQL. Para obtener un número preciso, debe realizar un recuento completo de filas debido a la naturaleza de MVCC . Hay una manera de acelerar esto drásticamente si el recuento no tiene que ser exacto como parece ser en su caso.
En lugar de obtener el recuento exacto ( lento con tablas grandes):
Obtienes una estimación cercana como esta ( extremadamente rápido ):
Qué tan cerca esté la estimación depende de si corres lo
ANALYZE
suficiente. Suele estar muy cerca.Consulte las preguntas frecuentes de la Wiki de PostgreSQL .
O la página wiki dedicada para el rendimiento de conteo (*) .
Mejor todavía
El artículo en el PostgreSQL Wiki
sefue un poco descuidado . Ignoró la posibilidad de que pueda haber varias tablas con el mismo nombre en una base de datos, en diferentes esquemas. Para dar cuenta de eso:O mejor aun
Más rápido, más simple, más seguro, más elegante. Consulte el manual sobre tipos de identificadores de objetos .
Úselo
to_regclass('myschema.mytable')
en Postgres 9.4+ para evitar excepciones para nombres de tablas no válidos:TABLESAMPLE SYSTEM (n)
en Postgres 9.5+Como comentó @a_horse , la cláusula recién agregada para el
SELECT
comando podría ser útil si las estadísticas enpg_class
no están lo suficientemente actualizadas por alguna razón. Por ejemplo:autovacuum
correr.INSERT
oDELETE
.TEMPORARY
tablas (que no están cubiertas porautovacuum
).Esto solo mira una selección aleatoria de bloques n % (
1
en el ejemplo) y cuenta las filas en ella. Una muestra más grande aumenta el costo y reduce el error, su elección. La precisión depende de más factores:FILLFACTOR
espacio ocupado por bloque. Si se distribuye de manera desigual en la tabla, es posible que la estimación sea incorrecta.En la mayoría de los casos, la estimación de
pg_class
será más rápida y precisa.Respuesta a la pregunta real
Y si ...
Si. Puede usar una subconsulta con
LIMIT
:Postgres realmente deja de contar más allá del límite dado, obtiene un recuento exacto y actual para hasta n filas (500000 en el ejemplo) y n de lo contrario. Sin
pg_class
embargo, no tan rápido como la estimación .fuente
tablesample
cláusula: por ejemploselect count(*) * 100 as cnt from mytable tablesample system (1);
SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;
(Lo pregunto porque estoy tratando de obtener un recuento de una consulta arbitraria que ya podría tener una cláusula de límite)ORDER BY something
mientras no puede usar un índice o con funciones agregadas). Aparte de eso, solo se procesa el número limitado de filas de la subconsulta.Hice esto una vez en una aplicación de postgres ejecutando:
Luego, examina la salida con una expresión regular o una lógica similar. Para un SELECT * simple, la primera línea de salida debería verse así:
Puede usar el
rows=(\d+)
valor como una estimación aproximada del número de filas que se devolverán, luego solo haga el valor realSELECT COUNT(*)
si la estimación es, digamos, menos de 1,5 veces su umbral (o cualquier número que considere que tiene sentido para su aplicación).Según la complejidad de su consulta, este número puede volverse cada vez menos preciso. De hecho, en mi aplicación, a medida que agregamos uniones y condiciones complejas, se volvió tan inexacto que fue completamente inútil, incluso para saber cómo dentro de una potencia de 100 cuántas filas habríamos devuelto, por lo que tuvimos que abandonar esa estrategia.
Pero si su consulta es lo suficientemente simple como para que Pg pueda predecir con un margen de error razonable cuántas filas devolverá, puede funcionar para usted.
fuente
Referencia extraída de este Blog.
Puede utilizar a continuación para consultar y encontrar el recuento de filas.
Usando pg_class:
Usando pg_stat_user_tables:
fuente
En Oracle, puede utilizar
rownum
para limitar el número de filas devueltas. Supongo que también existe una construcción similar en otros SQL. Entonces, para el ejemplo que dio, podría limitar el número de filas devueltas a 500001 y aplicar uncount(*)
entonces:fuente
count(*)
con rownum, 1 s sin el uso de rownum). Sí,SELECT count(*) cnt FROM table
siempre devolverá 1 fila, pero con la condición LIMIT, devolverá "500001" cuando el tamaño de la tabla sea superior a 500000 y <tamaño> cuando el tamaño de la tabla sea <= 500000.¿Qué tan ancha es la columna de texto?
Con GROUP BY no hay mucho que pueda hacer para evitar un escaneo de datos (al menos un escaneo de índice).
Yo lo recomiendo:
Si es posible, cambie el esquema para eliminar la duplicación de datos de texto. De esta manera, el recuento ocurrirá en un campo de clave externa estrecho en la tabla 'muchos'.
Alternativamente, crear una columna generada con un HASH del texto, luego AGRUPAR POR la columna de hash. Nuevamente, esto es para disminuir la carga de trabajo (escanee a través de un índice de columna estrecho)
Editar:
Tu pregunta original no coincidía con tu edición. No estoy seguro de si sabe que COUNT, cuando se usa con GROUP BY, devolverá el recuento de elementos por grupo y no el recuento de elementos en toda la tabla.
fuente
Puede obtener el recuento mediante la siguiente consulta (sin * ni ningún nombre de columna).
fuente
count(*)
.Para SQL Server (2005 o superior), un método rápido y confiable es:
Los detalles sobre sys.dm_db_partition_stats se explican en MSDN
La consulta agrega filas de todas las partes de una tabla (posiblemente) particionada.
index_id = 0 es una tabla desordenada (Heap) e index_id = 1 es una tabla ordenada (índice agrupado)
Aquí se detallan métodos aún más rápidos (pero poco fiables) .
fuente