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?
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?
Respostas:
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).
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**';
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)
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.
SELECT TABLE_NAME,SUM(TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'your_db'
GROUP BY TABLE_NAME;
É tudo o que você precisa.
mysql> SELECT TABLE_NAME,SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ngramsdb' GROUP BY TABLE_NAME;
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
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 |
+----------------+-----------------+
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.
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
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);';
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
Obtenha uma lista de tabelas para o seu banco de dados. Você pode obtê-lo usando
mysql -uroot -p mydb -e "show tables"
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
Executá-lo:
chmod +x script.sh; ./script.sh
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.
É 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.";
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.
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_len
variável do servidor, mas a partir do MariaDb 10.2.4, ele deve usar o padrão 1M.
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'
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.
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 .