Obtenez le nombre d'enregistrements pour toutes les tables de la base de données MySQL


347

Existe-t-il un moyen d'obtenir le nombre de lignes dans toutes les tables d'une base de données MySQL sans exécuter un SELECT count()sur chaque table?


1
Réponse étendue qui est également exacte pour InnoDB: stackoverflow.com/questions/24707814/…
gwideman

1
SELECT count (table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'YOUR_DB' donnera le nombre de tables dans votre base de données
shasi kanth

Réponses:


416
SELECT SUM(TABLE_ROWS) 
     FROM INFORMATION_SCHEMA.TABLES 
     WHERE TABLE_SCHEMA = '{your_db}';

Remarque dans la documentation: pour les tables InnoDB, le nombre de lignes n'est qu'une estimation approximative utilisée dans l'optimisation SQL. Vous devrez utiliser COUNT (*) pour les nombres exacts (ce qui est plus cher).


267
ou, si vous le souhaitez pour chaque table: SELECT nom_table, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{your_db}';
TheSoftwareJedi

5
Existe-t-il un autre moyen d'obtenir table_row et table_name? Parce que je veux un résultat exact et non une estimation approximative. Je vous remercie.
krunal shah

3
@krunalshah, C'est l'une des restrictions d'InnoDB. Voir dev.mysql.com/doc/refman/5.0/en/innodb-restrictions.html , section Restrictions sur les tables InnoDB, pour plus d'informations. Vous pouvez toujours utiliser un SELECT COUNT (*) FROM t, qui est cependant beaucoup plus lent
Marquage le

2
Jaitsu, non ce n'est pas. count (*) (ou plus réaliste count (id)) est ce que mysql utilise pour compter ses lignes n'est-ce pas? Dans tous les cas, je viens de le tester et j'ai obtenu un plus grand nombre pour l'appel count (), quoi que cela vaille.
codygman

2
SELECT TABLE_NAME, SUM (TABLE_ROWS) N FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{your_db}' group by TABLE_NAME;
PiyusG

175

Vous pouvez probablement mettre quelque chose ensemble avec la table Tables . Je ne l'ai jamais fait, mais il semble qu'il y ait une colonne pour TABLE_ROWS et une pour TABLE NAME .

Pour obtenir des lignes par table, vous pouvez utiliser une requête comme celle-ci:

SELECT table_name, table_rows
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '**YOUR SCHEMA**';

4
Existe-t-il un autre moyen d'obtenir table_row et table_name? Parce que je veux un résultat exact et non une estimation approximative. Je vous remercie.
krunal shah

1
comme l'a mentionné kuranl, cela ne renvoie qu'une estimation et renverra probablement des résultats différents lorsqu'il sera exécuté plusieurs fois
Kris

Les tables contenant au moins ~ 250 enregistrements semblent signaler un nombre différent de lignes chaque fois que j'exécute cette requête.
Arthur

Oups ... j'aurais aimé voir le mot "estimé" avant la main ... comme hier! La réponse ne devrait-elle pas être rejetée? Comme OP n'a pas demandé "d'estimation" et il semble idiot de penser qu'il peut souhaiter une estimation. "estimation" Pourrait éviter aux marrons comme moi de ne pas avoir "l'estimation"?
Kreeverp

111

Comme @Venkatramanan et d'autres, j'ai trouvé INFORMATION_SCHEMA.TABLES peu fiable (en utilisant InnoDB, MySQL 5.1.44), donnant des nombres de lignes différents chaque fois que je l'exécute, même sur des tables au repos. Voici un moyen relativement hacky (mais flexible / adaptable) de générer une grosse instruction SQL que vous pouvez coller dans une nouvelle requête, sans installer de gemmes Ruby ni d'autres choses.

SELECT CONCAT(
    'SELECT "', 
    table_name, 
    '" AS table_name, COUNT(*) AS exact_row_count FROM `', 
    table_schema,
    '`.`',
    table_name, 
    '` UNION '
) 
FROM INFORMATION_SCHEMA.TABLES 
WHERE table_schema = '**my_schema**';

Il produit une sortie comme celle-ci:

SELECT "func" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.func UNION                         
SELECT "general_log" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.general_log UNION           
SELECT "help_category" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.help_category UNION       
SELECT "help_keyword" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.help_keyword UNION         
SELECT "help_relation" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.help_relation UNION       
SELECT "help_topic" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.help_topic UNION             
SELECT "host" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.host UNION                         
SELECT "ndb_binlog_index" AS table_name, COUNT(*) AS exact_row_count FROM my_schema.ndb_binlog_index UNION 

Copiez et collez à l'exception de la dernière UNION pour obtenir une sortie agréable comme,

+------------------+-----------------+
| table_name       | exact_row_count |
+------------------+-----------------+
| func             |               0 |
| general_log      |               0 |
| help_category    |              37 |
| help_keyword     |             450 |
| help_relation    |             990 |
| help_topic       |             504 |
| host             |               0 |
| ndb_binlog_index |               0 |
+------------------+-----------------+
8 rows in set (0.01 sec)

2
Merci, j'espérais que je n'aurais pas besoin d'installer de plugins / gemmes pour obtenir les décomptes exacts.
bradvido

Prend trop de temps à exécuter en cas de grand nombre de tables dans la base de données.
ollamh

1
ajouter "select * from (" au début et ") comme ordre de sortie par exact_row_count desc" à la fin de la requête générée après avoir supprimé la dernière UNION pour obtenir l'ordre par nombre de tables desc
Raghavendra

Pour exclure des vues: WHERE table_schema = ' my_schema ' et TABLE_TYPE LIKE '% TABLE%'
Watson

39

Je viens de courir:

show table status;

Cela vous donnera le nombre de lignes pour CHAQUE table plus un tas d'autres informations. J'avais l'habitude d'utiliser la réponse sélectionnée ci-dessus, mais c'est beaucoup plus facile.

Je ne sais pas si cela fonctionne avec toutes les versions, mais j'utilise 5.5 avec le moteur InnoDB.


5
Malheureusement, si vous utilisez InnoDB, cette approche souffre des mêmes inexactitudes que les autres méthodes décrites ci-dessus. Par exemple, j'ai une table InnoDB qui a environ 65 000 lignes, mais ces méthodes indiquent ici qu'elle en a de 350 000 à plus de 780 000.
PeterToTheThird

Pour une base de données avec quelques lignes, c'est assez précis (ou assez précis pour mes besoins). Il m'a donné 1086 lignes pour une table que COUNT (*) a rapporté 904 lignes.
Magne

De loin la meilleure réponse. J'utilise InnoDB mais je n'ai besoin que d'une commande rapide pour connaître l'ordre de grandeur.
Nemo

Sérieusement, j'aimerais que cela soit accepté. Ne pas utiliser InnoDB et me donne une réponse exacte.
Kolob Canyon

1
Le nombre de lignes n'est pas précis mais "Auto_increment" peut vous donner un nombre précis si vous n'avez supprimé aucune ligne de ces tables.
Peter T.

13
 SELECT TABLE_NAME,SUM(TABLE_ROWS) 
 FROM INFORMATION_SCHEMA.TABLES 
 WHERE TABLE_SCHEMA = 'your_db' 
 GROUP BY TABLE_NAME;

C'est tout ce dont vous avez besoin.


1
produit des lignes de table estimées - comparer à "mysql_num_rows ($ tableresult)"
Kreeverp

1
c'est la meilleure réponse en fait! Aussi le plus simple à exécuter depuis mysql cli:mysql> SELECT TABLE_NAME,SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ngramsdb' GROUP BY TABLE_NAME;
loretoparisi

11

Cette procédure stockée répertorie les tables, compte les enregistrements et produit un nombre total d'enregistrements à la fin.

Pour l'exécuter après avoir ajouté cette procédure:

CALL `COUNT_ALL_RECORDS_BY_TABLE` ();

-

La procédure:

DELIMITER $$

CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `COUNT_ALL_RECORDS_BY_TABLE`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE TNAME CHAR(255);

DECLARE table_names CURSOR for 
    SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE();

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN table_names;   

DROP TABLE IF EXISTS TCOUNTS;
CREATE TEMPORARY TABLE TCOUNTS 
  (
    TABLE_NAME CHAR(255),
    RECORD_COUNT INT
  ) ENGINE = MEMORY; 


WHILE done = 0 DO

  FETCH NEXT FROM table_names INTO TNAME;

   IF done = 0 THEN
    SET @SQL_TXT = CONCAT("INSERT INTO TCOUNTS(SELECT '" , TNAME  , "' AS TABLE_NAME, COUNT(*) AS RECORD_COUNT FROM ", TNAME, ")");

    PREPARE stmt_name FROM @SQL_TXT;
    EXECUTE stmt_name;
    DEALLOCATE PREPARE stmt_name;  
  END IF;

END WHILE;

CLOSE table_names;

SELECT * FROM TCOUNTS;

SELECT SUM(RECORD_COUNT) AS TOTAL_DATABASE_RECORD_CT FROM TCOUNTS;

END

8

Manière simple:

SELECT
  TABLE_NAME, SUM(TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '{Your_DB}'
GROUP BY TABLE_NAME;

Exemple de résultat:

+----------------+-----------------+
| TABLE_NAME     | SUM(TABLE_ROWS) |
+----------------+-----------------+
| calls          |            7533 |
| courses        |             179 |
| course_modules |             298 |
| departments    |              58 |
| faculties      |             236 |
| modules        |             169 |
| searches       |           25423 |
| sections       |             532 |
| universities   |              57 |
| users          |           10293 |
+----------------+-----------------+

4

Il y a un peu de hack / contournement à ce problème d'estimation.

Auto_Increment - pour une raison quelconque, cela renvoie un nombre de lignes beaucoup plus précis pour votre base de données si l'incrémentation automatique est configurée sur les tables.

J'ai trouvé cela en explorant pourquoi les informations de la table d'affichage ne correspondaient pas aux données réelles.

SELECT
table_schema 'Database',
SUM(data_length + index_length) AS 'DBSize',
SUM(TABLE_ROWS) AS DBRows,
SUM(AUTO_INCREMENT) AS DBAutoIncCount
FROM information_schema.tables
GROUP BY table_schema;


+--------------------+-----------+---------+----------------+
| Database           | DBSize    | DBRows  | DBAutoIncCount |
+--------------------+-----------+---------+----------------+
| Core               |  35241984 |   76057 |           8341 |
| information_schema |    163840 |    NULL |           NULL |
| jspServ            |     49152 |      11 |            856 |
| mysql              |   7069265 |   30023 |              1 |
| net_snmp           |  47415296 |   95123 |            324 |
| performance_schema |         0 | 1395326 |           NULL |
| sys                |     16384 |       6 |           NULL |
| WebCal             |    655360 |    2809 |           NULL |
| WxObs              | 494256128 |  530533 |        3066752 |
+--------------------+-----------+---------+----------------+
9 rows in set (0.40 sec)

Vous pouvez ensuite facilement utiliser PHP ou autre pour renvoyer le maximum des 2 colonnes de données pour donner la "meilleure estimation" pour le nombre de lignes.

c'est à dire

SELECT
table_schema 'Database',
SUM(data_length + index_length) AS 'DBSize',
GREATEST(SUM(TABLE_ROWS), SUM(AUTO_INCREMENT)) AS DBRows
FROM information_schema.tables
GROUP BY table_schema;

L'incrémentation automatique sera toujours +1 * (nombre de tables), mais même avec 4000 tables et 3 millions de lignes, c'est une précision de 99,9%. Beaucoup mieux que les lignes estimées.

La beauté de ceci est que le nombre de lignes renvoyé dans performance_schema est également effacé pour vous, car le plus grand ne fonctionne pas sur les valeurs nulles. Cependant, cela peut être un problème si vous n'avez pas de tables avec incrémentation automatique.


3

Vous pouvez essayer ça. Cela fonctionne bien pour moi.

SELECT IFNULL(table_schema,'Total') "Database",TableCount 
FROM (SELECT COUNT(1) TableCount,table_schema 
      FROM information_schema.tables 
      WHERE table_schema NOT IN ('information_schema','mysql') 
      GROUP BY table_schema WITH ROLLUP) A;

2

Si vous utilisez la base de données information_schema, vous pouvez utiliser ce code mysql (la partie where fait que la requête n'affiche pas les tables qui ont une valeur nulle pour les lignes):

SELECT TABLE_NAME, TABLE_ROWS
FROM `TABLES`
WHERE `TABLE_ROWS` >=0

1

La requête suivante produit une requête (nother) qui obtiendra la valeur de count (*) pour chaque table, à partir de chaque schéma, répertoriée dans information_schema.tables. Le résultat complet de la requête présentée ici - toutes les lignes prises ensemble - comprend une instruction SQL valide se terminant par un point-virgule - sans «union» pendante. L'union pendante est évitée en utilisant une union dans la requête ci-dessous.

select concat('select "', table_schema, '.', table_name, '" as `schema.table`,
                          count(*)
                 from ', table_schema, '.', table_name, ' union ') as 'Query Row'
  from information_schema.tables
 union
 select '(select null, null limit 0);';

1

Voici ce que je fais pour obtenir le nombre réel (pas d'utilisation du schéma)

C'est plus lent mais plus précis.

C'est un processus en deux étapes à

  1. Obtenez la liste des tables pour votre base de données. Vous pouvez l'obtenir en utilisant

    mysql -uroot -p mydb -e "show tables"
  2. Créez et assignez la liste des tables à la variable de tableau dans ce script bash (séparées par un seul espace comme dans le code ci-dessous)

    array=( table1 table2 table3 )
    
    for i in "${array[@]}"
    do
        echo $i
        mysql -uroot mydb -e "select count(*) from $i"
    done
  3. Exécuter:

    chmod +x script.sh; ./script.sh

1

Une autre option: pour les non InnoDB, il utilise les données de information_schema.TABLES (car c'est plus rapide), pour InnoDB - sélectionnez count (*) pour obtenir le décompte précis. Il ignore également les vues.

SET @table_schema = DATABASE();
-- or SET @table_schema = 'my_db_name';

SET GROUP_CONCAT_MAX_LEN=131072;
SET @selects = NULL;

SELECT GROUP_CONCAT(
        'SELECT "', table_name,'" as TABLE_NAME, COUNT(*) as TABLE_ROWS FROM `', table_name, '`'
        SEPARATOR '\nUNION\n') INTO @selects
  FROM information_schema.TABLES
  WHERE TABLE_SCHEMA = @table_schema
        AND ENGINE = 'InnoDB'
        AND TABLE_TYPE = "BASE TABLE";

SELECT CONCAT_WS('\nUNION\n',
  CONCAT('SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND ENGINE <> "InnoDB" AND TABLE_TYPE = "BASE TABLE"'),
  @selects) INTO @selects;

PREPARE stmt FROM @selects;
EXECUTE stmt USING @table_schema;
DEALLOCATE PREPARE stmt;

Si votre base de données contient beaucoup de grandes tables InnoDB, le comptage de toutes les lignes peut prendre plus de temps.


0

Voici comment je compte les TABLES et TOUS LES ENREGISTREMENTS en utilisant PHP:

$dtb = mysql_query("SHOW TABLES") or die (mysql_error());
$jmltbl = 0;
$jml_record = 0;
$jml_record = 0;

while ($row = mysql_fetch_array($dtb)) { 
    $sql1 = mysql_query("SELECT * FROM " . $row[0]);            
    $jml_record = mysql_num_rows($sql1);            
    echo "Table: " . $row[0] . ": " . $jml_record record . "<br>";      
    $jmltbl++;
    $jml_record += $jml_record;
}

echo "--------------------------------<br>$jmltbl Tables, $jml_record > records.";

Pourquoi n'utilisez-vous pas count (*) si vous ignorez les données?
Svetoslav Marinov

0

L'affiche voulait le nombre de lignes sans compter, mais n'a pas précisé quel moteur de table. Avec InnoDB, je ne connais qu'une seule façon, c'est de compter.

Voici comment je cueille mes pommes de terre:

# Put this function in your bash and call with:
# rowpicker DBUSER DBPASS DBNAME [TABLEPATTERN]
function rowpicker() {
    UN=$1
    PW=$2
    DB=$3
    if [ ! -z "$4" ]; then
        PAT="LIKE '$4'"
        tot=-2
    else
        PAT=""
        tot=-1
    fi
    for t in `mysql -u "$UN" -p"$PW" "$DB" -e "SHOW TABLES $PAT"`;do
        if [ $tot -lt 0 ]; then
            echo "Skipping $t";
            let "tot += 1";
        else
            c=`mysql -u "$UN" -p"$PW" "$DB" -e "SELECT count(*) FROM $t"`;
            c=`echo $c | cut -d " " -f 2`;
            echo "$t: $c";
            let "tot += c";
        fi;
    done;
    echo "total rows: $tot"
}

Je ne fais aucune affirmation à ce sujet autre que le fait que c'est un moyen vraiment laid mais efficace pour obtenir le nombre de lignes dans chaque table de la base de données, quel que soit le moteur de table et sans avoir à avoir la permission d'installer des procédures stockées, et sans avoir besoin d'installer rubis ou php. Oui, c'est rouillé. Oui ça compte. count (*) est précis.


0

Sur la base de la réponse de @ Nathan ci-dessus, mais sans avoir besoin de "supprimer l'union finale" et avec l'option de trier la sortie, j'utilise le SQL suivant. Il génère une autre instruction SQL qui s'exécute ensuite:

select CONCAT( 'select * from (\n', group_concat( single_select SEPARATOR ' UNION\n'), '\n ) Q order by Q.exact_row_count desc') as sql_query
from (
    SELECT CONCAT(
        'SELECT "', 
        table_name, 
        '" AS table_name, COUNT(1) AS exact_row_count
        FROM `', 
        table_schema,
        '`.`',
        table_name, 
        '`'
    ) as single_select
    FROM INFORMATION_SCHEMA.TABLES 
    WHERE table_schema = 'YOUR_SCHEMA_NAME'
      and table_type = 'BASE TABLE'
) Q 

Vous avez besoin d'une valeur de group_concat_max_lenvariable de serveur suffisamment grande, mais à partir de MariaDb 10.2.4, elle devrait par défaut être 1M.


0

Le code ci-dessous génère la requête de sélection pour tous les contes. Il suffit de supprimer le dernier "UNION ALL", de sélectionner tous les résultats et de coller une nouvelle fenêtre de requête à exécuter.

SELECT 
concat('select ''', table_name ,''' as TableName, COUNT(*) as RowCount from ' , table_name , ' UNION ALL ')  as TR FROM
information_schema.tables where 
table_schema = 'Database Name'

-1

Si vous voulez les nombres exacts, utilisez le script ruby ​​suivant. Vous avez besoin de Ruby et RubyGems.

Installez les gemmes suivantes:

$> gem install dbi
$> gem install dbd-mysql

Fichier: count_table_records.rb

require 'rubygems'
require 'dbi'

db_handler = DBI.connect('DBI:Mysql:database_name:localhost', 'username', 'password')

# Collect all Tables
sql_1 = db_handler.prepare('SHOW tables;')
sql_1.execute
tables = sql_1.map { |row| row[0]}
sql_1.finish

tables.each do |table_name|
  sql_2 = db_handler.prepare("SELECT count(*) FROM #{table_name};")
  sql_2.execute
  sql_2.each do |row|
    puts "Table #{table_name} has #{row[0]} rows."
  end
  sql_2.finish
end

db_handler.disconnect

Revenez à la ligne de commande:

$> ruby count_table_records.rb

Production:

Table users has 7328974 rows.

-4

Si vous connaissez le nombre de tables et leurs noms, et en supposant qu'elles ont chacune des clés primaires, vous pouvez utiliser une jointure croisée en combinaison avec COUNT(distinct [column])pour obtenir les lignes provenant de chaque table:

SELECT 
   COUNT(distinct t1.id) + 
   COUNT(distinct t2.id) + 
   COUNT(distinct t3.id) AS totalRows
FROM firstTable t1, secondTable t2, thirdTable t3;

Voici un exemple SQL Fiddle .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.