sql >> Base de Datos >  >> RDS >> PostgreSQL

Manera rápida de descubrir el recuento de filas de una tabla en PostgreSQL

Se sabe que contar filas en tablas grandes es lento en PostgreSQL. El modelo MVCC requiere un conteo completo de filas vivas para obtener un número preciso. Hay soluciones alternativas para acelerarlo drásticamente si el conteo no tiene que ser exacto como parece ser en tu caso.

(¡Recuerde que incluso un conteo "exacto" está potencialmente muerto al llegar!)

Recuento exacto

Lento para tablas grandes.
Con operaciones de escritura simultáneas, puede quedar obsoleto en el momento en que lo obtenga.

SELECT count(*) AS exact_count FROM myschema.mytable;
Estimación

Extremadamente rápido :

SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';

Por lo general, la estimación es muy cercana. Qué tan cerca depende de si ANALYZE o VACUUM se ejecutan lo suficiente, donde "suficiente" se define por el nivel de actividad de escritura en su tabla.

Estimación más segura

Lo anterior ignora la posibilidad de varias tablas con el mismo nombre en una base de datos, en diferentes esquemas. Para dar cuenta de eso:

SELECT c.reltuples::bigint AS estimate
FROM   pg_class c
JOIN   pg_namespace n ON n.oid = c.relnamespace
WHERE  c.relname = 'mytable'
AND    n.nspname = 'myschema';

El elenco de bigint formatea el real número muy bien, especialmente para grandes conteos.

Mejor estimación

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;

Más rápido, más simple, más seguro, más elegante. Consulte el manual sobre tipos de identificadores de objetos.

Reemplace 'myschema.mytable'::regclass con to_regclass('myschema.mytable') en Postgres 9.4+ para obtener nada en lugar de una excepción para nombres de tablas no válidos. Ver:

  • Cómo verificar si una tabla existe en un esquema dado

Mejor estimación aún (por un costo adicional muy bajo)

Podemos hacer lo que hace el planificador de Postgres. Citando los Ejemplos de estimación de filas en el manual:

Estos números son actuales a partir del último VACUUM o ANALYZE en la mesa. Luego, el planificador obtiene el número real actual de páginas en la tabla (esta es una operación económica que no requiere un escaneo de la tabla). Si eso es diferente de relpages entonces reltuples se escala en consecuencia para llegar a una estimación actual del número de filas.

Postgres usa estimate_rel_size definido en src/backend/utils/adt/plancat.c , que también cubre el caso de la esquina sin datos en pg_class porque la relación nunca fue vaciada. Podemos hacer algo similar en SQL:

Forma mínima

SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM   pg_class
WHERE  oid = 'mytable'::regclass;  -- your table here

Seguro y explícito

SELECT (CASE WHEN c.reltuples < 0 THEN NULL       -- never vacuumed
             WHEN c.relpages = 0 THEN float8 '0'  -- empty table
             ELSE c.reltuples / c.relpages END
      * (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
       )::bigint
FROM   pg_class c
WHERE  c.oid = 'myschema.mytable'::regclass;      -- schema-qualified table here

No se rompe con tablas vacías y tablas que nunca han visto VACUUM o ANALYZE . El manual en pg_class :

Si la tabla nunca ha sido aspirada o analizada, reltuples contiene -1 lo que indica que se desconoce el número de filas.

Si esta consulta devuelve NULL , ejecuta ANALYZE o VACUUM para la mesa y repetir. (Alternativamente, podría estimar el ancho de fila en función de los tipos de columna como lo hace Postgres, pero eso es tedioso y propenso a errores).

Si esta consulta devuelve 0 , la mesa parece estar vacía. Pero yo ANALYZE asegurarse. (Y tal vez verifique su autovacuum configuración.)

Normalmente, block_size es 8192. current_setting('block_size')::int cubre raras excepciones.

Las calificaciones de tabla y esquema lo hacen inmune a cualquier search_path y alcance.

De cualquier manera, la consulta siempre toma <0.1 ms para mí.

Más recursos web:

  • Preguntas frecuentes de Postgres Wiki
  • Las páginas wiki de Postgres para estimaciones de conteo y rendimiento de conteo(*)

TABLESAMPLE SYSTEM (n) en PostgreSQL 9.5+

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);

Como comentó @a_horse, la cláusula añadida para SELECT El comando puede ser útil si las estadísticas en pg_class no son lo suficientemente actuales por alguna razón. Por ejemplo:

  • Sin autovacuum corriendo.
  • Inmediatamente después de un gran INSERT / UPDATE / DELETE .
  • TEMPORARY tablas (que no están cubiertas por autovacuum ).

Esto solo mira un n aleatorio % (1 en el ejemplo) selección de bloques y cuenta filas en él. Una muestra más grande aumenta el costo y reduce el error, usted elige. La precisión depende de más factores:

  • Distribución del tamaño de fila. Si un bloque determinado contiene filas más anchas de lo habitual, el recuento es más bajo de lo habitual, etc.
  • Tuplas muertas o un FILLFACTOR ocupan espacio por bloque. Si se distribuye de manera desigual en la tabla, es posible que la estimación no sea correcta.
  • Errores generales de redondeo.

Normalmente, la estimación de pg_class será más rápido y más preciso.

Respuesta a la pregunta real

Primero, necesito saber el número de filas en esa tabla, si el recuento total es mayor que alguna constante predefinida,

Y si es...

... es posible en el momento en que el conteo pase mi valor constante, detendrá el conteo (y no esperará a que finalice el conteo para informar que el conteo de filas es mayor).

Sí. Puede usar una subconsulta con LIMIT :

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

Postgres en realidad deja de contar más allá del límite dado, obtiene un exacto y actual contar hasta n filas (500000 en el ejemplo) y n de lo contrario. No tan rápido como la estimación en pg_class , sin embargo.