Obter contagens de registros para todas as tabelas no banco de dados MySQL

347

Existe uma maneira de obter a contagem de linhas em todas as tabelas em um banco de dados MySQL sem executar um SELECT count()em cada tabela?

Marca
fonte
11
Resposta estendida que também é precisa para o InnoDB: stackoverflow.com/questions/24707814/…
gwideman
11
SELECT count (nome_da_tabela) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'YOUR_DB' fornecerá o número de tabelas em seu banco de dados
shasi kanth

Respostas:

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

Porém, observe os documentos: Para tabelas do InnoDB, a contagem de linhas é apenas uma estimativa aproximada usada na otimização do SQL. Você precisará usar COUNT (*) para contagens exatas (que são mais caras).

Odeia_
fonte
266
ou, se você desejar para cada tabela: SELECT table_name, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{your_db}';
TheSoftwareJedi
5
Existe alguma outra maneira de obter table_row e table_name? Porque eu quero o resultado exato, não estimativa aproximada. Obrigado.
precisa saber é o seguinte
3
@krunalshah, esta é uma das restrições do InnoDB. Consulte dev.mysql.com/doc/refman/5.0/en/innodb-restrictions.html , seção Restrições nas tabelas do InnoDB, para obter mais informações. Você sempre pode usar um SELECT COUNT (*) FROM t, que, no entanto, é muito mais lento
Marcando
2
Jaitsu, não, não é. count (*) (ou mais realisticamente count (id)) é o que o mysql usa para contar suas linhas, não é? De qualquer forma, eu apenas testei e obtive um número maior para a chamada count (), o que vale a pena.
Codygman
2
SELECT TABLE_NAME, SUM (TABLE_ROWS) N FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = grupo '{your_db}' de TABLE_NAME;
PiyusG
175

Você provavelmente pode colocar algo junto com a tabela Tables . Eu nunca fiz isso, mas parece que ele tem uma coluna para TABLE_ROWS e uma para TABLE NAME .

Para obter linhas por tabela, você pode usar uma consulta como esta:

SELECT table_name, table_rows
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '**YOUR SCHEMA**';
gpojd
fonte
4
Existe alguma outra maneira de obter table_row e table_name? Porque eu quero o resultado exato, não estimativa aproximada. Obrigado.
precisa saber é o seguinte
11
como kuranl mencionado este retorna apenas uma estimativa e, provavelmente, irá retornar resultados diferentes quando executar um par de vezes
Kris
As tabelas com pelo menos ~ 250 registros parecem relatar um número diferente de linhas cada vez que executo essa consulta.
Arthur
Opa ... gostaria de ter visto a palavra "Estimada" antes da mão ... como ontem! A resposta não deve ser rejeitada? Como o OP não pediu "estimado" e parece bobagem pensar que ele pode querer uma estimativa. "estimativa" Poderia salvar quilombolas como eu de perder a "estimativa"?
Kreeverp
111

Como @Venkatramanan e outros, achei o INFORMAÇÕES_SCHEMA.TABLES não confiável (usando o InnoDB, MySQL 5.1.44), fornecendo contagens de linhas diferentes cada vez que o rodava, mesmo em tabelas desativadas. Aqui está uma maneira relativamente hacky (mas flexível / adaptável) de gerar uma grande instrução SQL que você pode colar em uma nova consulta, sem instalar gemas e outras coisas do Ruby.

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**';

Produz resultados como este:

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 

Copie e cole, exceto o último UNION, para obter uma boa saída, como,

+------------------+-----------------+
| 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)
Nathan
fonte
2
Obrigado, esperava não ter que instalar nenhum plug-in / gema para obter contagens exatas.
bradvido 2/09/14
Demora muito para ser executado no caso de um grande número de tabelas no banco de dados.
Ollamh
11
adicionar "SELECT * FROM (" no início e ") como ordem de saída por desc exact_row_count" no final da consulta gerada após a remoção última UNIÃO obter ordem por desc contagem de tabela
Raghavendra
Para excluir visualizações: WHERE table_schema = ' my_schema ' e TABLE_TYPE LIKE '% TABLE%'
Watson
38

Eu apenas corro:

show table status;

Isso fornecerá a contagem de linhas para TODAS as tabelas, além de várias outras informações. Eu costumava usar a resposta selecionada acima, mas isso é muito mais fácil.

Não tenho certeza se isso funciona com todas as versões, mas estou usando o 5.5 com o mecanismo InnoDB.

djburdick
fonte
5
Infelizmente, se você estiver usando o InnoDB, essa abordagem sofrerá as mesmas imprecisões dos outros métodos descritos acima. Por exemplo, eu tenho uma tabela do InnoDB que possui aproximadamente 65.000 linhas, mas esses métodos aqui relatam que ela tem de 350.000 a mais de 780.000.
PeterToTheThird
Para um banco de dados com poucas linhas, é bastante preciso (ou preciso o suficiente para minhas necessidades). Me deram 1086 linhas para uma tabela que COUNT (*) relatou 904 linhas.
Magne
De longe a melhor resposta. Eu uso o InnoDB, mas só preciso de um comando rápido para saber a ordem de magnitude.
Nemo
Sério, gostaria que isso fosse aceito. Não usar o InnoDB e me fornece uma resposta exata.
Kolob Canyon
11
O número de linhas não é preciso, mas "Acréscimo automático" pode fornecer um número exato se você não excluiu nenhuma linha dessas tabelas.
Peter T.
13
 SELECT TABLE_NAME,SUM(TABLE_ROWS) 
 FROM INFORMATION_SCHEMA.TABLES 
 WHERE TABLE_SCHEMA = 'your_db' 
 GROUP BY TABLE_NAME;

É tudo o que você precisa.

Gustavo Castro
fonte
11
produz linhas de tabela estimadas - compare com "mysql_num_rows ($ tableresult)"
Kreeverp
11
essa é a melhor resposta, na verdade! Também o mais simples de ser executado a partir do mysql cli:mysql> SELECT TABLE_NAME,SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ngramsdb' GROUP BY TABLE_NAME;
loretoparisi
11

Este procedimento armazenado lista tabelas, conta registros e produz um número total de registros no final.

Para executá-lo após adicionar este procedimento:

CALL `COUNT_ALL_RECORDS_BY_TABLE` ();

-

O procedimento:

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
Jake Drew
fonte
8

Maneira simples:

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

Exemplo de resultado:

+----------------+-----------------+
| 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 |
+----------------+-----------------+
Eduardo Cuomo
fonte
4

Há um pouco de hack / solução alternativa para esse problema de estimativa.

Auto_Increment - por algum motivo, isso retorna uma contagem de linhas muito mais precisa para o seu banco de dados se você tiver um incremento automático configurado nas tabelas.

Encontrei isso ao explorar por que as informações da tabela show não correspondiam aos dados reais.

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)

Você pode usar facilmente o PHP ou o que quer que seja para retornar o máximo das 2 colunas de dados para fornecer a "melhor estimativa" para a contagem de linhas.

ie

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;

O incremento automático sempre terá +1 * (contagem de tabelas) de linhas desativadas, mas mesmo com 4.000 tabelas e 3 milhões de linhas, é 99,9% preciso. Muito melhor que as linhas estimadas.

A vantagem disso é que as contagens de linhas retornadas em performance_schema também são apagadas, porque o maior não funciona com valores nulos. Isso pode ser um problema se você não tiver tabelas com incremento automático.

user3260912
fonte
3

Você pode tentar isso. Está funcionando bem pra mim.

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;
Nimesh07
fonte
2

Se você usar o banco de dados information_schema, poderá usar este código mysql (a parte where faz com que a consulta não mostre tabelas que possuem um valor nulo para linhas):

SELECT TABLE_NAME, TABLE_ROWS
FROM `TABLES`
WHERE `TABLE_ROWS` >=0
Robin Manoli
fonte
1

A consulta a seguir produz uma consulta (nother) que obterá o valor de count (*) para cada tabela, de cada esquema, listado em information_schema.tables. Todo o resultado da consulta mostrada aqui - todas as linhas juntas - compreendem uma instrução SQL válida que termina em ponto e vírgula - sem 'união' pendente. A união pendente é evitada pelo uso de uma união na consulta abaixo.

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);';
user1575139
fonte
1

Isto é o que eu faço para obter a contagem real (sem usar o esquema)

É mais lento, mas mais preciso.

É um processo de duas etapas no

  1. Obtenha uma lista de tabelas para o seu banco de dados. Você pode obtê-lo usando

    mysql -uroot -p mydb -e "show tables"
  2. Crie e atribua a lista de tabelas à variável da matriz neste script bash (separado por um único espaço, como no código abaixo)

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

    chmod +x script.sh; ./script.sh
lsaffie
fonte
1

Mais uma opção: para não InnoDB, ele usa dados de information_schema.TABLES (como é mais rápido), para InnoDB - selecione count (*) para obter a contagem precisa. Também ignora visualizações.

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;

Se o seu banco de dados tiver muitas tabelas grandes do InnoDB, a contagem de todas as linhas poderá levar mais tempo.

filimonov
fonte
0

É assim que eu conto TABLES e TODOS OS REGISTROS usando 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.";
koswara1482
fonte
Por que você não usa count (*) se ignora os dados?
Svetoslav Marinov
0

O cartaz queria a contagem de linhas sem contar, mas não especificou qual mecanismo de tabela. Com o InnoDB, eu sei apenas uma maneira, que é contar.

É assim que eu pego minhas batatas:

# 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"
}

Não estou fazendo nenhuma afirmação sobre isso, a não ser que essa é uma maneira realmente feia, mas eficaz, de obter quantas linhas existem em cada tabela no banco de dados, independentemente do mecanismo de tabela e sem ter que ter permissão para instalar procedimentos armazenados e sem a necessidade de instalar ruby ou php. Sim, está enferrujado. Sim, conta. contagem (*) é precisa.

apotek
fonte
0

Com base na resposta de @ Nathan acima, mas sem a necessidade de "remover a união final" e com a opção de classificar a saída, eu uso o seguinte SQL. Ele gera outra instrução SQL que é executada:

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 

Você precisa de um valor suficientemente grande da group_concat_max_lenvariável do servidor, mas a partir do MariaDb 10.2.4, ele deve usar o padrão 1M.

Adão
fonte
0

O código abaixo gera a consulta de seleção para todos os contos. Basta excluir o último "UNION ALL", selecionar todos os resultados e colar uma nova janela de consulta para executar.

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'
grande
fonte
-1

Se você quiser os números exatos, use o seguinte script ruby. Você precisa de Ruby e RubyGems.

Instale as seguintes gemas:

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

Arquivo: 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

Volte para a linha de comando:

$> ruby count_table_records.rb

Resultado:

Table users has 7328974 rows.
Michael Voigt
fonte
-4

Se você souber o número de tabelas e seus nomes, e supondo que cada um deles possua chaves primárias, poderá usar uma junção cruzada em combinação com COUNT(distinct [column])para obter as linhas que vêm de cada tabela:

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

Aqui está um exemplo do SQL Fiddle .

AdamMc331
fonte