J'ai besoin de connaître le nombre de lignes dans un tableau pour calculer un pourcentage. Si le nombre total est supérieur à une constante prédéfinie, j'utiliserai la valeur constante. Sinon, j'utiliserai le nombre réel de lignes.
Je peux utiliser SELECT count(*) FROM table
. Mais si ma valeur constante est 500 000 et que j'ai 5 000 000 000 de lignes dans ma table, compter toutes les lignes perdra beaucoup de temps.
Est-il possible d'arrêter de compter dès que ma valeur constante est dépassée?
J'ai besoin du nombre exact de lignes uniquement tant qu'il est inférieur à la limite donnée. Sinon, si le nombre est supérieur à la limite, j'utilise la valeur limite à la place et je veux la réponse le plus rapidement possible.
Quelque chose comme ça:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
sql
postgresql
count
row
Renato Dinhani
la source
la source
Réponses:
Le comptage des lignes dans les grandes tables est connu pour être lent dans PostgreSQL. Pour obtenir un nombre précis, il doit effectuer un décompte complet des lignes en raison de la nature du MVCC . Il existe un moyen d' accélérer considérablement ce processus si le décompte ne doit pas être exact comme il semble l'être dans votre cas.
Au lieu d'obtenir le décompte exact ( lent avec de grandes tables):
Vous obtenez une estimation précise comme celle-ci ( extrêmement rapide ):
La précision de l'estimation dépend du fait que vous en exécutez
ANALYZE
suffisamment. C'est généralement très proche.Consultez la FAQ du wiki PostgreSQL .
Ou la page wiki dédiée pour les performances de count (*) .
Mieux encore
L'article paru dans le Wiki PostgreSQL
estétait un peu bâclé . Il a ignoré la possibilité qu'il puisse y avoir plusieurs tables du même nom dans une base de données - dans différents schémas. Pour en tenir compte:Ou mieux encore
Plus rapide, plus simple, plus sûr, plus élégant. Consultez le manuel sur les types d'identificateurs d'objets .
Utilisez
to_regclass('myschema.mytable')
dans Postgres 9.4+ pour éviter les exceptions pour les noms de table non valides:TABLESAMPLE SYSTEM (n)
dans Postgres 9.5+Comme @a_horse l'a commenté , la clause nouvellement ajoutée pour la
SELECT
commande peut être utile si les statistiques depg_class
ne sont pas assez actuelles pour une raison quelconque. Par exemple:autovacuum
course.INSERT
ouDELETE
.TEMPORARY
tables (qui ne sont pas couvertes parautovacuum
).Cela ne regarde qu'une sélection aléatoire de n % (
1
dans l'exemple) de blocs et compte les lignes. Un plus grand échantillon augmente le coût et réduit l'erreur, votre choix. La précision dépend de plusieurs facteurs:FILLFACTOR
espace occupé par bloc. Si elle est inégalement répartie sur le tableau, l'estimation peut être erronée.Dans la plupart des cas, l'estimation de
pg_class
sera plus rapide et plus précise.Réponse à la question réelle
Et si c'est ...
Oui. Vous pouvez utiliser une sous
LIMIT
- requête avec :Postgres arrête réellement de compter au-delà de la limite donnée, vous obtenez un exact et actuel pour jusqu'à n lignes (500000 dans l'exemple), et n sinon. Pas aussi rapide que l'estimation
pg_class
, cependant.la source
tablesample
clause: par exempleselect count(*) * 100 as cnt from mytable tablesample system (1);
SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;
(Je demande parce que j'essaie d'obtenir un décompte à partir d'une requête arbitraire qui pourrait déjàORDER BY something
alors qu'il ne peut pas utiliser d'index, ou avec des fonctions d'agrégation). En dehors de cela, seul le nombre limité de lignes de la sous-requête est traité.Je l'ai fait une fois dans une application postgres en exécutant:
Examinez ensuite la sortie avec une expression régulière ou une logique similaire. Pour un simple SELECT *, la première ligne de sortie devrait ressembler à ceci:
Vous pouvez utiliser la
rows=(\d+)
valeur comme une estimation approximative du nombre de lignes qui seraient renvoyées, puis ne faire le réel queSELECT COUNT(*)
si l'estimation est, par exemple, inférieure à 1,5 fois votre seuil (ou tout autre nombre que vous jugez pertinent pour votre application).Selon la complexité de votre requête, ce nombre peut devenir de moins en moins précis. En fait, dans mon application, au fur et à mesure que nous ajoutions des jointures et des conditions complexes, cela devenait si inexact qu'il était complètement inutile, même de savoir comment, dans une puissance de 100, le nombre de lignes que nous avions renvoyées, nous avons donc dû abandonner cette stratégie.
Mais si votre requête est suffisamment simple pour que Pg puisse prédire dans une marge d'erreur raisonnable le nombre de lignes qu'elle renverra, cela peut fonctionner pour vous.
la source
Référence tirée de ce blog.
Vous pouvez utiliser ci-dessous pour rechercher le nombre de lignes.
Utilisation de pg_class:
Utilisation de pg_stat_user_tables:
la source
Dans Oracle, vous pouvez utiliser
rownum
pour limiter le nombre de lignes renvoyées. Je suppose qu'une construction similaire existe également dans d'autres SQL. Ainsi, pour l'exemple que vous avez donné, vous pouvez limiter le nombre de lignes renvoyées à 500001 et appliquercount(*)
alors:la source
count(*)
avec rownum, 1 s sans l'utilisation de rownum). Oui,SELECT count(*) cnt FROM table
il retournera toujours 1 ligne, mais avec la condition LIMIT, il retournera "500001" lorsque la taille de la table est supérieure à 500000 et <taille> lorsque la taille de la table <= 500000.Quelle est la largeur de la colonne de texte?
Avec un GROUP BY, vous ne pouvez pas faire grand chose pour éviter une analyse de données (au moins une analyse d'index).
Je recommande:
Si possible, modifiez le schéma pour supprimer la duplication des données texte. De cette façon, le décompte se produira sur un champ de clé étrangère étroite dans la table «plusieurs».
Vous pouvez également créer une colonne générée avec un HASH du texte, puis GROUP BY la colonne de hachage. Encore une fois, cela permet de réduire la charge de travail (parcourir un index de colonne étroit)
Éditer:
Votre question d'origine ne correspondait pas tout à fait à votre modification. Je ne sais pas si vous savez que COUNT, lorsqu'il est utilisé avec un GROUP BY, renverra le nombre d'éléments par groupe et non le nombre d'éléments dans l'ensemble du tableau.
la source
Vous pouvez obtenir le nombre par la requête ci-dessous (sans * ni aucun nom de colonne).
la source
count(*)
.Pour SQL Server (2005 ou supérieur), une solution rapide et fiable méthode est:
Les détails sur sys.dm_db_partition_stats sont expliqués dans MSDN
La requête ajoute des lignes de toutes les parties d'une table (éventuellement) partitionnée.
index_id = 0 est une table non ordonnée (Heap) et index_id = 1 est une table ordonnée (index clusterisé)
Des méthodes encore plus rapides (mais peu fiables) sont détaillées ici.
la source