Le moyen le plus rapide de compter le nombre exact de lignes dans un très grand tableau?

234

Je suis tombé sur des articles qui indiquent que SELECT COUNT(*) FROM TABLE_NAMEcela sera lent lorsque le tableau aura beaucoup de lignes et de colonnes.

J'ai une table qui pourrait contenir même des milliards de lignes [elle a environ 15 colonnes]. Existe-t-il un meilleur moyen d'obtenir le compte EXACT du nombre de lignes d'une table?

Veuillez considérer les éléments suivants avant votre réponse:

  • Je recherche une solution indépendante du fournisseur de base de données. C'est OK s'il couvre MySQL , Oracle , MS SQL Server . Mais s'il n'y a vraiment pas de solution indépendante du fournisseur de base de données, je me contenterai de différentes solutions pour différents fournisseurs de base de données.

  • Je ne peux utiliser aucun autre outil externe pour ce faire. Je recherche principalement une solution basée sur SQL.

  • Je ne peux plus normaliser la conception de ma base de données. Il est déjà en 3NF et d'ailleurs beaucoup de code a déjà été écrit autour de lui.

Swaranga Sarma
la source
4
Et juste curieux de savoir pourquoi il est nécessaire d'avoir le nombre exact de lignes instantanées lorsque vous en avez des milliards ...
zerkms
2
N'espérerions-nous pas tous que cette construction particulière a été optimisée par notre fournisseur de base de données?
KevinDTimm
5
@Swaranga, pouvez-vous expliquer un peu plus à quoi sert cet objectif de maintenance de la base de données qui doit connaître le nombre exact de lignes dans la table? Je ne peux pas imaginer. Et comme Kevin le dit, s'il y avait un moyen plus rapide que COUNT (*), le fournisseur du SGBD devrait (devrait) sûrement ré-implémenter COUNT (*) pour l'utiliser ...
Tony Andrews
3
Sûrement, si la table est souvent écrite, votre nombre exact ne sera exact qu'à un moment donné et peut même ne pas être précis si d'autres processus écrivent dans la table, sauf si vous mettez un verrou de table sur la requête.
Steve Ford
2
Vous pouvez utiliser des déclencheurs d'insertion et de suppression pour conserver un nombre variable?
paparazzo

Réponses:

246

Réponse simple:

  • Solution indépendante du fournisseur de base de données = utiliser la norme = COUNT(*)
  • Il existe des solutions SQL Server approximatives mais n'utilisez pas COUNT (*) = hors de portée

Remarques:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey) juste au cas où

Éditer:

Exemple SQL Server (1,4 milliard de lignes, 12 colonnes)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 descente, 5 min 46 s, compte = 1 401 659 700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2 courses, toutes les deux en moins d'une seconde, comptez = 14016596970

Le second a moins de lignes = faux. Serait le même ou plus selon les écritures (les suppressions sont effectuées en dehors des heures ici)

gbn
la source
9
Nope, COUNT(*) = COUNT(key). C'est tout simplement faux. S'il n'y a pas de NOT NULLcontrainte - alors elles peuvent être différentes (dans les résultats aussi bien que dans le plan d'exécution).
zerkms
14
@zerkmsby: Pour COUNT (clé), je voulais dire COUNT (clé primaire) qui ne devrait pas être nullable. Je vais clarifier
gbn
8
avec (NOLOCK) n'est pas quelque chose qui lui permet de fonctionner en production, et cela peut conduire à un décompte inexact. Lorsque vous utilisez cet indice, il empêche les verrous, mais les effets secondaires sur une boîte de production sont que vous pouvez compter deux fois les lignes dans certaines situations ou ignorer les lignes dans d'autres situations. NOLOCK est préférable d'utiliser sur une table qui n'est pas en cours d'écriture car il permet des "lectures sales". Ne conseillez pas aux gens d'utiliser cet indice à moins qu'ils ne comprennent pleinement les conséquences
Davos
4
@mishrsud La seule requête précise est le SELECT COUNT (*), mais c'est lent. Vous pouvez avoir soit exact et lent, soit grossier et rapide. Ce que vous ferez dépendra de ce qui est le plus important pour l'objectif pour lequel vous avez besoin du décompte. NO LOCK peut inclure ou même exclure des lignes qui sont en cours de transaction ou qui déplacent des pages pour une raison quelconque.
Davos
5
@gbn très belle solution, pouvez-vous nous dire à quoi ça sert index_id < 2?
commit le
29

Le moyen le plus rapide de loin sur MySQL est:

SHOW TABLE STATUS;

Vous obtiendrez instantanément toutes vos tables avec le nombre de lignes (qui est le total) ainsi que de nombreuses informations supplémentaires si vous le souhaitez.

salbahra
la source
1
Smart way..with cela, vous pouvez obtenir le nombre de lignes de plusieurs tables dans 1 requête.
Deval Khandelwal
avez-vous exécuté sur db des tables contenant ~ un milliard d'entrées comme @gbn et avez-vous remarqué l'heure?
KNU
quelle valeur est le nombre total de lignes pour toutes les tables de la base de données? Et ceux-ci sont approximatifs - que faire si vous voulez des valeurs exactes de nombre de lignes?
Kreeverp
2
cela ne fonctionne pas du tout, sur INNODB par exemple, le moteur de stockage lit quelques lignes et extrapole pour deviner le nombre de lignes
Martijn Scheffer
10

Je suis tombé sur des articles qui indiquent que SELECT COUNT (*) FROM TABLE_NAME sera lent lorsque la table a beaucoup de lignes et beaucoup de colonnes.

Cela dépend de la base de données. Certains accélèrent le décompte, par exemple en gardant une trace de si des lignes sont vivantes ou mortes dans l'index, permettant une analyse d'index uniquement pour extraire le nombre de lignes. D'autres ne le font pas et nécessitent par conséquent de visiter la table entière et de compter les lignes en direct une par une. Soit sera lent pour une immense table.

Notez que vous pouvez généralement extraire une bonne estimation en utilisant des outils d'optimisation de requête, des statistiques de table, etc. Dans le cas de PostgreSQL, par exemple, vous pouvez analyser la sortie de explain count(*) from yourtableet obtenir une estimation assez bonne du nombre de lignes. Ce qui m'amène à votre deuxième question.

J'ai une table qui pourrait contenir même des milliards de lignes [elle a environ 15 colonnes]. Existe-t-il un meilleur moyen d'obtenir le compte EXACT du nombre de lignes d'une table?

Sérieusement? :-) Vous voulez vraiment dire le nombre exact d'une table avec des milliards de lignes? Êtes-vous vraiment sûr? :-)

Si vous le faites vraiment , vous pouvez garder une trace du total à l'aide de déclencheurs, mais faites attention à la simultanéité et aux blocages si vous le faites.

Denis de Bernardy
la source
Oui Denis, le décompte exact est requis. :(
Swaranga Sarma
5
C'est une chance que les gestionnaires de Google soient plus raisonnables que votre patron ... Imaginez combien cela serait lent s'il renvoyait le nombre exact de résultats de recherche pour chacune de vos requêtes au lieu de s'en tenir à un nombre estimé.
Denis de Bernardy
Au moins, tu compatis avec moi. Que diriez-vous d'une seule solution Oracle? Cela réduira mon problème dans une certaine mesure. Actuellement, le client utilise Oracle; donc si je propose une solution de contournement uniquement pour Oracle, cela fera l'affaire [pour le moment]. :)
Swaranga Sarma
6
"Oui Denis, le nombre exact est requis. :(" - je ne peux que spéculer. Le processus de maintenance de la base de données découvre-t-il qu'il y a 42 123 876 lignes dans le tableau A, puis crée 42 123 876 lignes vides dans le tableau B, puis parcourt le tableau A et mettre à jour les lignes du tableau B ...? Ou est-ce plus fou que ça? ;-)
Tony Andrews
1
La transaction 2 ne peut pas commencer avant que la transaction 1 ne soit validée. Sans la mise à jour de la "table des comptes", de nombreuses transactions de mise à jour pourraient s'exécuter en parallèle. Avec la "table des décomptes", chaque transaction doit "obtenir un ticket" pour mettre à jour son décompte. Ainsi, les transactions commencent à faire la queue au distributeur de billets (le planificateur décide qui sera le prochain à verrouiller la table des comptes).
Erwin Smout
10

Existe-t-il un meilleur moyen d'obtenir le compte EXACT du nombre de lignes d'une table?

Pour répondre simplement à votre question, non .

Si vous avez besoin d'une méthode indépendante du SGBD pour ce faire, la méthode la plus rapide sera toujours:

SELECT COUNT(*) FROM TableName

Certains fournisseurs de SGBD peuvent avoir des moyens plus rapides qui ne fonctionneront que pour leurs systèmes. Certaines de ces options sont déjà publiées dans d'autres réponses.

COUNT(*) devrait être optimisé par le SGBD (au moins toute base de données digne de PROD) de toute façon, alors n'essayez pas de contourner leurs optimisations.

En passant:
je suis sûr que beaucoup de vos autres requêtes prennent également beaucoup de temps à terminer en raison de la taille de votre table. Tout problème de performances doit probablement être résolu en réfléchissant à la conception de votre schéma en pensant à la vitesse. Je sais que vous avez dit que ce n'était pas une option à changer, mais il se pourrait que les requêtes de plus de 10 minutes ne soient pas non plus une option. La 3e NF n'est pas toujours la meilleure approche lorsque vous avez besoin de vitesse, et parfois les données peuvent être partitionnées dans plusieurs tables si les enregistrements ne doivent pas être stockés ensemble. Quelque chose à quoi penser...

Jesse Webb
la source
10

J'ai obtenu ce script d'une autre question / réponse de StackOverflow:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

Ma table a 500 millions d'enregistrements et les retours ci-dessus en moins de 1 ms. Pendant ce temps,

SELECT COUNT(id) FROM MyTable

prend 39 minutes, 52 secondes!

Ils donnent exactement le même nombre de lignes (dans mon cas, exactement 519326012).

Je ne sais pas si ce serait toujours le cas.

JakeJ
la source
Pouvez-vous ajouter un paramètre pour obtenir le nombre de lignes avec cette requête? Exemple: Sélectionnez COUNT (1) FROM TABLENAME WHERE ColumnFiled = '1' Avec votre requête?
VnDevil
C'est le nombre - le nombre de lignes (enregistrements) est le "nombre" dans ce cas. "500 millions d'enregistrements" était un nombre approximatif et "519326012" était le nombre exact de lignes, ou nombre. Lignes = enregistrements = nombre.
JakeJ
9

Vous pouvez essayer ce sp_spaceused (Transact-SQL)

Affiche le nombre de lignes, l'espace disque réservé et l'espace disque utilisé par une table, une vue indexée ou une file d'attente Service Broker dans la base de données actuelle, ou affiche l'espace disque réservé et utilisé par l'ensemble de la base de données.

confitures
la source
Sp_spaceused ne me donnera-t-il pas un nombre approximatif?
Swaranga Sarma
1
Pour info: ceci utilise sys.dm_db_partition_stats en interne
gbn
6

Si l'édition de SQL Server est 2005/2008, vous pouvez utiliser des DMV pour calculer le nombre de lignes dans une table:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

Pour le moteur de base de données SQL Server 2000, sysindexes fonctionnera, mais il est fortement déconseillé de l'utiliser dans les futures éditions de SQL Server car il pourrait être supprimé dans un avenir proche.

Exemple de code tiré de: Comment obtenir le nombre de lignes de tableau rapidement et sans douleur

Alireza Maddah
la source
C'est approximatif, pas exact : voir ma réponse s'il vous plaît
gbn
Connaissez-vous un exemple où ce n'est pas exact? AFAIK, cela ne dépend pas des statistiques mises à jour.
Alireza Maddah
5

j'utilise

select /*+ parallel(a) */  count(1) from table_name a;
Mainsh S
la source
select / * + parallel (a) * / count (1) from table_name a
Mainsh S
5

Je suis loin d'être aussi expert que d'autres qui ont répondu, mais j'avais un problème avec une procédure que j'utilisais pour sélectionner une ligne au hasard dans un tableau (pas trop pertinent) mais j'avais besoin de connaître le nombre de lignes dans ma table de référence pour calculer l'indice aléatoire. En utilisant le travail traditionnel Count (*) ou Count (1), mais je recevais parfois jusqu'à 2 secondes pour que ma requête s'exécute. Donc à la place (pour ma table nommée 'tbl_HighOrder') j'utilise:

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

Cela fonctionne très bien et les temps de requête dans Management Studio sont nuls.

john rains
la source
1
FWIW, vous devez mentionner le fournisseur de base de données que vous utilisez; Je pense que la déclaration serait légèrement différente selon le fournisseur.
ToolmakerSteve
5

Eh bien, en retard de 5 ans et je ne sais pas si cela aide:

J'essayais de compter le non. de lignes dans une table SQL Server à l'aide de MS SQL Server Management Studio et a rencontré une erreur de débordement, puis j'ai utilisé ce qui suit:

sélectionnez count_big (1) FROM [dbname]. [dbo]. [FactSampleValue];

Le résultat :

24296650578 rangées

Antagoniste de Kaliyug
la source
5

J'ai trouvé ce bon article SQL Server - COMMENT FAIRE: récupérer rapidement le nombre de lignes exactes pour la table à partir demartijnh1 laquelle donne un bon récapitulatif pour chaque scénario.

J'ai besoin que cela soit développé là où je dois fournir un compte basé sur une condition spécifique et quand je figurerai cette partie, je mettrai à jour cette réponse plus loin.

En attendant, voici les détails de l'article:

Méthode 1:

Requete:

SELECT COUNT(*) FROM Transactions 

Commentaires:

Effectue une analyse complète de la table. Lent sur les grandes tables.

Méthode 2:

Requete:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

Commentaires:

Un moyen rapide de récupérer le nombre de lignes. Dépend des statistiques et est inexact.

Exécutez DBCC UPDATEUSAGE (Database) WITH COUNT_ROWS, ce qui peut prendre beaucoup de temps pour les grandes tables.

Méthode 3:

Requete:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

Commentaires:

La façon dont le studio de gestion SQL compte les lignes (regardez les propriétés des tables, le stockage, le nombre de lignes). Très rapide, mais toujours un nombre approximatif de lignes.

Méthode 4:

Requete:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

Commentaires:

Fonctionnement rapide (mais pas aussi rapide que la méthode 2) et tout aussi important, fiable.

Thierry
la source
Merci! Astuce vraiment utile. Je n'ai pas l'autorisation d'afficher les tables système, la méthode 4 n'est donc pas moi. Cependant, la méthode 3 est assez bonne.
Nicholas Humphrey
3

Je ne pense pas qu'il existe une solution générale toujours la plus rapide: certains SGBDR / versions ont une optimisation spécifique pour SELECT COUNT(*) utiliser des options plus rapides tandis que d'autres se contentent de scanner les tables. Vous devez vous rendre sur les sites de documentation / support du second ensemble, qui nécessiteront probablement une requête plus spécifique pour être écrite, généralement une requête qui atteint un index d'une manière ou d'une autre.

ÉDITER:

Voici une pensée qui pourrait fonctionner, selon votre schéma et la distribution des données: avez-vous une colonne indexée qui fait référence à une valeur croissante, un ID croissant numérique, par exemple, ou même un horodatage ou une date? Ensuite, en supposant que les suppressions ne se produisent pas, il devrait être possible de stocker le nombre jusqu'à une valeur récente (date d'hier, valeur d'ID la plus élevée à un point d'échantillonnage récent) et d'ajouter le nombre au-delà, ce qui devrait se résoudre très rapidement dans l'index . Très dépendant des valeurs et des indices, bien sûr, mais applicable à presque toutes les versions de n'importe quel SGBD.

Mike Woodhouse
la source
J'espère vraiment que tout SGBD décent utiliserait un index pour SELECT COUNT(*). Même MySQL le fait apparemment ....
sleske
en supposant que les suppressions ne se produisent pas - sérieusement ?? ; p
ToolmakerSteve
3

Je suis en retard à cette question, mais voici ce que vous pouvez faire avec MySQL (car j'utilise MySQL). Je partage mes observations ici:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>

Résultat
Nombre de lignes: 508534
Sortie console : Lignes affectées: 0 Lignes trouvées: 1 Avertissements: 0 Durée pour 1 requête: 0,125 sec.
Prend un certain temps pour une table avec un grand nombre de lignes, mais le nombre de lignes est très exact.

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"

Résultat
Nombre de lignes: 511235
Sortie console : Lignes affectées: 0 Lignes trouvées: 1 Avertissements: 0 Durée pour 1 requête: 0,250 s Résumé: Le nombre de lignes n'est pas exact.

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

Résultat
Nombre de lignes: 507806
Sortie console : Lignes affectées: 0 Lignes trouvées: 48 Avertissements: 0 Durée pour 1 requête: 1,701 sec.
Le nombre de lignes n'est pas exact.

Je ne suis pas un expert de MySQL ou de base de données, mais j'ai trouvé que pour les très grandes tables, vous pouvez utiliser l'option 2 ou 3 et avoir une «bonne idée» du nombre de lignes présentes.

J'avais besoin d'obtenir ces nombres de lignes pour afficher certaines statistiques sur l'interface utilisateur. Avec les requêtes ci-dessus, je savais que le nombre total de lignes était supérieur à 500 000, j'ai donc proposé des statistiques telles que "Plus de 500 000 lignes" sans afficher le nombre exact de lignes.

Peut-être que je n'ai pas vraiment répondu à la question du PO, mais je partage ce que j'ai fait dans une situation où de telles statistiques étaient nécessaires. Dans mon cas, montrer les lignes approximatives était acceptable et donc ce qui précède a fonctionné pour moi.

sunitkatkar
la source
2

Pas exactement une solution indépendante du SGBD, mais au moins votre code client ne verra pas la différence ...

Créez une autre table T avec une seule ligne et un champ entier N 1 , et créez INSERT TRIGGER qui exécute simplement:

UPDATE T SET N = N + 1

Créez également un DELETE TRIGGER qui exécute:

UPDATE T SET N = N - 1

Un SGBD digne de ce nom garantira l'atomicité des opérations au-dessus de 2 , et N contiendra le nombre précis de lignes à tout moment, ce qui est alors très rapide à obtenir simplement:

SELECT N FROM T

Bien que les déclencheurs soient spécifiques au SGBD, la sélection entre T ne l'est pas et votre code client n'aura pas besoin de changer pour chaque SGBD pris en charge.

Cependant, cela peut avoir des problèmes d'évolutivité si la table nécessite beaucoup INSERT ou DELETE, en particulier si vous ne COMMITZ PAS immédiatement après INSERT / DELETE.


1 Ces noms ne sont que des espaces réservés - utilisez quelque chose de plus significatif dans la production.

2 Ie N ne peut pas être modifié par une transaction simultanée entre la lecture et l'écriture sur N, tant que la lecture et l'écriture sont effectuées dans une seule instruction SQL.

Branko Dimitrijevic
la source
2

Une réponse littéralement folle, mais si vous avez mis en place une sorte de système de réplication (pour un système avec un milliard de lignes, je l'espère), vous pouvez utiliser un estimateur approximatif (comme MAX(pk) ), divisez cette valeur par le nombre d'esclaves vous avez, exécutez plusieurs requêtes en parallèle.

Pour la plupart, vous partitionneriez les requêtes entre les esclaves en fonction de la meilleure clé (ou de la clé primaire, je suppose), de cette manière (nous allons utiliser 250000000 comme lignes / esclaves):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

Mais vous n'avez besoin que de SQL. Quel buste. Ok, alors disons que tu es un sadomasochiste. Sur le maître (ou l'esclave le plus proche), vous auriez probablement besoin de créer une table pour cela:

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

Ainsi, au lieu d'avoir uniquement les sélections en cours d'exécution dans vos esclaves, vous devriez faire un insert, semblable à ceci:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

Vous pouvez rencontrer des problèmes avec les esclaves écrivant sur une table sur le maître. Vous devrez peut-être devenir encore plus sadique - je veux dire, créatif:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

Vous devriez finalement avoir un esclave qui existe en dernier dans le chemin parcouru par le graphe de réplication, par rapport au premier esclave. Cet esclave devrait maintenant avoir toutes les autres contre-valeurs et devrait avoir ses propres valeurs. Mais au moment où vous avez terminé, il y a probablement des lignes ajoutées, vous devrez donc en insérer une autre compensant le max pk enregistré dans votre counter_table et le max pk actuel.

À ce stade, vous devez effectuer une fonction d'agrégation pour déterminer le nombre total de lignes, mais c'est plus facile car vous l'exécuterez sur au plus le "nombre d'esclaves que vous avez et modifiez".

Si vous êtes dans la situation où vous avez des tables séparées dans les esclaves, vous pouvez UNIONobtenir toutes les lignes dont vous avez besoin.

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

Ou vous savez, soyez un peu moins fou et migrez vos données vers un système de traitement distribué, ou utilisez peut-être une solution de Data Warehousing (qui vous donnera également de superbes données à l'avenir).

Notez que cela dépend de la façon dont votre réplication est configurée. Étant donné que le principal goulot d'étranglement sera probablement un stockage persistant, si vous avez un stockage cruddy ou des magasins de données mal séparés avec un bruit de voisin élevé, cela vous exécutera probablement plus lentement que d'attendre un seulSELECT COUNT(*) ...

Mais si vous avez une bonne réplication, vos gains de vitesse doivent être directement liés au nombre ou aux esclaves. En fait, s'il faut 10 minutes pour exécuter la requête de comptage seule et que vous avez 8 esclaves, vous réduisez votre temps à moins de quelques minutes. Peut-être une heure pour aplanir les détails de cette solution.

Bien sûr, vous n'obtiendrez jamais vraiment une réponse incroyablement précise car cette résolution distribuée introduit un peu de temps où les lignes peuvent être supprimées et insérées, mais vous pouvez essayer d'obtenir un verrou distribué des lignes dans la même instance et obtenir un nombre précis des lignes du tableau à un moment donné.

En fait, cela semble impossible, car vous êtes essentiellement bloqué avec une solution SQL uniquement, et je ne pense pas que vous disposiez d'un mécanisme pour exécuter une requête fragmentée et verrouillée sur plusieurs esclaves, instantanément. Peut-être que si vous contrôliez le fichier journal de réplication ... ce qui signifie que vous feriez littéralement tourner des esclaves à cette fin, ce qui est sans doute plus lent que d'exécuter la requête de comptage sur une seule machine de toute façon.

Il y a donc mes deux sous en 2013.

Yangmun Choi
la source
2

Si le déclencheur d'insertion est trop coûteux à utiliser, mais qu'un déclencheur de suppression peut être proposé, et qu'il y a une incrémentation automatiqueid , après avoir compté une fois la table entière et se souvenir du compte comme last-countetlast-counted-id ,

puis chaque jour il suffit de compter pour id> last-counted-id, d'ajouter cela à last-countet de stocker le nouveaulast-counted-id .

Le déclencheur de suppression décrémenterait le dernier compte, si l'ID de l'enregistrement supprimé <= le dernier ID compté.

ToolmakerSteve
la source
.. désolé je n'ai pas le temps de montrer le SQL qui serait utilisé (mon SQL est rouillé). Si quelqu'un veut modifier ma réponse pour ajouter du SQL, ce serait bien!
ToolmakerSteve
1

Si vous avez une structure de table typique avec une colonne de clé primaire à incrémentation automatique dans laquelle les lignes ne sont jamais supprimées, ce qui suit sera le moyen le plus rapide pour déterminer le nombre d'enregistrements et devrait fonctionner de manière similaire dans la plupart des bases de données conformes à ANSI:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

Je travaille avec des tables MS SQL contenant des milliards de lignes qui nécessitent des temps de réponse inférieurs à la seconde pour les données, y compris le nombre d'enregistrements. Un SELECT COUNT (*) similaire prendrait quelques minutes à comparer.

KevinS
la source
1
Pas tout à fait vrai - que se passe-t-il si une INSERTtransaction est annulée? Cette valeur de clé primaire serait absente, de sorte que le nombre d'enregistrements réel serait inférieur de un à la valeur maximale.
Sir Crispalot
Il pourrait y avoir des lacunes dans l'ordre. Habituellement le résultat de rollbacks.
Osa E
En fait, il y a une modification de cette réponse qui pourrait être beaucoup plus rapide que count(*)si un fournisseur de base de données n'a pas suffisamment optimisé count(*): chaque jour, gardez une trace du dernier auto-index et de son nombre correspondant, puis demandez un nombre d'enregistrements après cela. Peut également gérer deletes si ajouter un déclencheur lors de la suppression qui diminue le total précédent , si l'identifiant de l'enregistrement supprimé <= ce dernier auto-index.
ToolmakerSteve
1

Pour le serveur SQL, essayez ceci

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 
Abhishek B Patel
la source
0

sélectionner des lignes dans sysindexes où id = Object_ID ('TableName') et indid <2

Enzero
la source
0

Mettez un index sur une colonne. Cela devrait permettre à l'optimiseur d'effectuer une analyse complète des blocs d'index, au lieu d'une analyse complète de la table. Cela réduira considérablement vos coûts d'E / S. Regardez le plan d'exécution avant et après. Mesurez ensuite le temps de l'horloge murale dans les deux sens.

EvilTeach
la source
Si une table a des milliards de lignes sans index sur aucune colonne, alors il y aura des problèmes de performances généralisés, bien au-delà du besoin exprimé dans la question d'origine .. mais bon que vous mentionniez cela (ne supposez rien!) :)
ToolmakerSteve
0

Si vous utilisez Oracle, qu'en est-il (en supposant que les statistiques de la table sont mises à jour):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed affichera l'heure de la dernière collecte des statistiques.

Diogo Ferreira
la source
0

Avec PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'
Dorian
la source
-1

Dans SQL Server 2016, je peux simplement vérifier les propriétés de la table, puis sélectionner l'onglet `` Stockage '' - cela me donne le nombre de lignes, l'espace disque utilisé par la table, l'espace d'index utilisé, etc.

SenSei
la source
Il cherchait un database vendor independent solution. Cela nécessite également une interface graphique et ne peut pas être automatisé. De plus, ce n'est pas plus rapide que COUNT (*)
Frieder
-3

Peut-être un peu en retard mais cela pourrait aider les autres pour MSSQL

; AVEC RecordCount AS (SELECT ROW_NUMBER () OVER (ORDER BY COLUMN_NAME) AS [RowNumber] FROM TABLE_NAME) SELECT MAX (RowNumber) FROM RecordCount

Justus Swanevelder
la source
C'est bien pire que COUNT (), sauf si nous sommes TRÈS chanceux et que l'optimiseur parvient à l'optimiser en COUNT () - pourquoi le demander à SORT sur une colonne aléatoire?!?
dsz