有没有一种方法可以获取 MySQL 数据库中所有表中的行数,而无需在每个表上运行 SELECT count()
?
SELECT SUM(TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '{your_db}';
Note from the docs though:对于 InnoDB 表,行数只是一个粗略的估计,用于 SQL 优化。您需要使用 COUNT(*) 进行精确计数(这更昂贵)。
您可能可以将某些东西与 Tables table 放在一起。我从来没有做过,但它看起来有一个 TABLE_ROWS 列和一个 TABLE NAME 列。
要获取每个表的行数,可以使用如下查询:
SELECT table_name, table_rows
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '**YOUR SCHEMA**';
像@Venkatramanan 和其他人一样,我发现 INFORMATION_SCHEMA.TABLES 不可靠(使用 InnoDB、MySQL 5.1.44),即使在静默表上运行它时也会给出不同的行数。这是一种生成大 SQL 语句的相对 hacky(但灵活/适应性强)的方法,您可以将其粘贴到新查询中,而无需安装 Ruby gems 和其他东西。
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**';
它产生如下输出:
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
复制并粘贴除了最后一个 UNION 以获得不错的输出,例如,
+------------------+-----------------+
| 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)
我只是运行:
show table status;
这将为您提供每个表的行数以及一堆其他信息。我曾经使用上面选择的答案,但这更容易。
我不确定这是否适用于所有版本,但我使用的是 5.5 和 InnoDB 引擎。
简单的方法:
SELECT
TABLE_NAME, SUM(TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '{Your_DB}'
GROUP BY TABLE_NAME;
结果示例:
+----------------+-----------------+
| 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 |
+----------------+-----------------+
SELECT TABLE_NAME,SUM(TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'your_db'
GROUP BY TABLE_NAME;
这就是你所需要的。
mysql> SELECT TABLE_NAME,SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ngramsdb' GROUP BY TABLE_NAME;
此存储过程列出表、统计记录并在最后生成记录总数。
添加此过程后运行它:
CALL `COUNT_ALL_RECORDS_BY_TABLE` ();
-
步骤:
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
这个估计问题有一些技巧/解决方法。
Auto_Increment - 如果您在表上设置了自动增量,由于某种原因,这将为您的数据库返回更准确的行数。
在探索为什么显示表信息与实际数据不匹配时发现了这一点。
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)
然后,您可以轻松地使用 PHP 或其他方法返回 2 个数据列的最大值,以给出行数的“最佳估计”。
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;
自动增量将始终关闭 +1 *(表计数)行,但即使有 4,000 个表和 300 万行,也有 99.9% 的准确率。比估计的行好得多。
这样做的美妙之处在于,performance_schema 中返回的行数也会为您删除,因为最大不适用于空值。但是,如果您没有具有自动增量功能的表,这可能是一个问题。
另一种选择:对于非 InnoDB,它使用来自 information_schema.TABLES 的数据(因为它更快),对于 InnoDB - 选择 count(*) 以获得准确的计数。它也忽略视图。
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;
如果您的数据库有很多大型 InnoDB 表,计算所有行可能需要更多时间。
PREPARE
之前添加了一行 SELECT CONCAT(@selects, ' ORDER BY TABLE_ROWS ') INTO @selects;
以获得更易读的输出,但这对我来说是最好的答案。
你可以试试这个。它对我来说很好。
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;
如果您使用数据库 information_schema,则可以使用此 mysql 代码(where 部分使查询不显示行具有空值的表):
SELECT TABLE_NAME, TABLE_ROWS
FROM `TABLES`
WHERE `TABLE_ROWS` >=0
以下查询生成一个(另一个)查询,它将从 information_schema.tables 中列出的每个模式中获取每个表的 count(*) 值。此处显示的查询的整个结果 - 所有行加在一起 - 包含一个以分号结尾的有效 SQL 语句 - 没有悬空的“联合”。通过在下面的查询中使用联合来避免悬空联合。
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);';
这是我为获得实际计数所做的(不使用架构)
它更慢但更准确。
这是一个两步过程
获取您的数据库的表列表。您可以使用 mysql -uroot -p mydb -e "show tables" 创建表列表并将其分配给此 bash 脚本中的数组变量(由单个空格分隔,就像在下面的代码中一样) array=( table1 table2 table3 ) for i in "${array[@]}" do echo $i mysql -uroot mydb -e "select count(*) from $i" done 运行:chmod +x script.sh; ./script.sh
这就是我使用 PHP 计算 TABLES 和 ALL RECORDS 的方式:
$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.";
海报想要不计算行数,但没有指定哪个表引擎。对于 InnoDB,我只知道一种方法,那就是计数。
这就是我挑选土豆的方式:
# 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"
}
我没有对此做出任何断言,除了这是一种非常丑陋但有效的方法来获取数据库中每个表中存在多少行,而不管表引擎如何,并且无需获得安装存储过程的权限,也无需安装红宝石或PHP。是的,它生锈了。是的,它很重要。 count(*) 是准确的。
基于上面@Nathan 的回答,但不需要“删除最终联合”并且可以选择对输出进行排序,我使用以下 SQL。它生成另一个 SQL 语句,然后运行:
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
您确实需要足够大的 group_concat_max_len
服务器变量值,但从 MariaDb 10.2.4 开始,它应该默认为 1M。
我不知道为什么这必须如此艰难,但这就是生活。这是我执行实际计数的 bash 脚本。只需将其保存为(例如 count_rows.sh ),使其可执行(例如 chmod 755 count_rows.sh ),然后运行它(例如 ./count_rows.sh )
#!/bin/bash
readarray -t TABLES < <(mysql --skip-column-names -u myuser -pmypassword mydbname -e "show tables")
# now we have an array like:
# TABLES='([0]="customer" [1]="order" [2]="product")'
# You can print out the array with:
#declare -p TABLES
for i in "${TABLES[@]}"
do
#echo $i
COUNT=$(mysql --skip-column-names -u username -pmypassword mydbname -e "select count(*) from $i")
echo $i : $COUNT
done
如果您想要确切的数字,请使用以下 ruby 脚本。你需要 Ruby 和 RubyGems。
安装以下宝石:
$> gem install dbi
$> gem install dbd-mysql
文件: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
回到命令行:
$> ruby count_table_records.rb
输出:
Table users has 7328974 rows.
下面的代码为所有故事生成选择查询。只需删除最后一个“UNION ALL”选择所有结果并粘贴一个新的查询窗口即可运行。
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'
如果您知道表的数量及其名称,并假设它们都有主键,则可以结合使用交叉联接和 COUNT(distinct [column])
来获取来自每个表的行:
SELECT
COUNT(distinct t1.id) +
COUNT(distinct t2.id) +
COUNT(distinct t3.id) AS totalRows
FROM firstTable t1, secondTable t2, thirdTable t3;
这是一个 SQL Fiddle 示例。