【问题标题】:Get record counts for all tables in MySQL database获取 MySQL 数据库中所有表的记录数
【发布时间】:2010-09-22 02:40:07
【问题描述】:

有没有一种方法可以获取 MySQL 数据库中所有表中的行数,而无需在每个表上运行 SELECT count()

【问题讨论】:

标签: mysql sql rowcount


【解决方案1】:

下面的代码生成所有故事的选择查询。只需删除最后一个“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'

【讨论】:

    【解决方案2】:

    基于上面@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。

    【讨论】:

      【解决方案3】:

      简单的方法:

      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 |
      +----------------+-----------------+
      

      【讨论】:

        【解决方案4】:
        SELECT SUM(TABLE_ROWS) 
             FROM INFORMATION_SCHEMA.TABLES 
             WHERE TABLE_SCHEMA = '{your_db}';
        

        Note from the docs though: 对于 InnoDB 表,行数只是一个粗略的估计,用于 SQL 优化。您需要使用 COUNT(*) 来进行精确计数(成本更高)。

        【讨论】:

        • 或者,如果你想为每个表:SELECT table_name, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{your_db}';
        • 还有其他方法可以获取 table_row 和 table_name 吗?因为我想要准确的结果而不是粗略的估计。谢谢。
        • @krunalshah,这是 InnoDB 的限制之一。有关更多信息,请参阅dev.mysql.com/doc/refman/5.0/en/innodb-restrictions.html,InnoDB 表的限制部分。您始终可以使用 SELECT COUNT(*) FROM t,但是速度要慢很多
        • Jaitsu,不,不是。 count(*) (或者更实际的 count(id))是 mysql 用来计算它的行​​数的东西,不是吗?无论如何,我只是对其进行了测试,并为 count() 调用获得了更大的数字,不管它值多少钱。
        • SELECT TABLE_NAME, SUM(TABLE_ROWS) N FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{your_db}' group by TABLE_NAME;
        【解决方案5】:

        这个估计问题有一些技巧/解决方法。

        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 个数据列的最大值,以给出行数的“最佳估计”。

        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 中返回的行数也会为您删除,因为最大不适用于空值。不过,如果您没有具有自动增量功能的表,这可能是个问题。

        【讨论】:

          【解决方案6】:

          你可以试试这个。它对我来说很好用。

          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;
          

          【讨论】:

            【解决方案7】:

            还有一个选项:对于非 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;,以便获得更具可读性的输出,但这是对我来说最好的答案。
            【解决方案8】:

            此存储过程列出表、统计记录并在最后生成记录总数。

            添加此过程后运行它:

            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
            

            【讨论】:

              【解决方案9】:

              如果您知道表的数量及其名称,并假设它们都有主键,则可以结合使用交叉连接和 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 示例。

              【讨论】:

                【解决方案10】:

                这是我为获取实际计数所做的(不使用架构)

                它更慢但更准确。

                这是一个两步过程

                1. 获取您的数据库的表列表。你可以使用

                  mysql -uroot -p mydb -e "show tables"
                  
                2. 在此 bash 脚本中创建表列表并将其分配给数组变量(由单个空格分隔,就像在下面的代码中一样)

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

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

                【讨论】:

                  【解决方案11】:

                  像@Venkatramanan 和其他人一样,我发现 INFORMATION_SCHEMA.TABLES 不可靠(使用 InnoDB、MySQL 5.1.44),即使在静默表上运行它时也会给出不同的行数。这是一种生成大 SQL 语句的相对简单(但灵活/适应性强)的方法,您可以将其粘贴到新查询中,而无需安装 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)
                  

                  【讨论】:

                  • 谢谢,我希望我不必安装任何插件/宝石来获得准确的计数。
                  • 如果数据库中有大量表,执行时间过长。
                  • 在删除最后一个 UNION 以按表计数 desc 获取顺序后,在生成的查询末尾添加“select * from (" at beginning and ") as output order by exact_row_count desc”
                  • 排除视图:WHERE table_schema = 'my_schema' and TABLE_TYPE LIKE '%TABLE%'
                  • 这对我来说是真正的答案。
                  【解决方案12】:

                  Poster 想要不计算行数,但没有指定哪个表引擎。对于 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"
                  }
                  

                  我对此没有任何断言,除了这是一种非常丑陋但有效的方法来获取数据库中每个表中存在多少行,而不管表引擎如何,并且无需获得安装存储过程的权限,并且无需需要安装 ruby​​ 或 php。是的,它生锈了。是的,它很重要。 count(*) 是准确的。

                  【讨论】:

                    【解决方案13】:

                    我只是跑:

                    show table status;
                    

                    这将为您提供每个表的行数以及一堆其他信息。 我曾经使用上面选择的答案,但这更容易。

                    我不确定这是否适用于所有版本,但我使用的是 5.5 和 InnoDB 引擎。

                    【讨论】:

                    • 不幸的是,如果您使用的是 InnoDB,则此方法与上述其他方法存在相同的不准确性。例如,我有一个 InnoDB 表,它有大约 65,000 行,但这里的这些方法报告它有 350,000 到 780,000 多行。
                    • 对于只有几行的数据库,它相当准确(或者,足够准确以满足我的需要)。对于 COUNT(*) 报告 904 行的表,它给了我 1086 行。
                    • 迄今为止最好的答案。我使用 InnoDB,但我只需要一个快速命令即可知道数量级。
                    • 说真的,希望这被接受。不使用 InnoDB 并给我确切的答案。
                    • 行数不准确,但如果您没有从此类表中删除任何行,“Auto_increment”可以为您提供准确的数字。
                    【解决方案14】:

                    以下查询生成一个(另一个)查询,该查询将从 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);';
                    

                    【讨论】:

                      【解决方案15】:
                       SELECT TABLE_NAME,SUM(TABLE_ROWS) 
                       FROM INFORMATION_SCHEMA.TABLES 
                       WHERE TABLE_SCHEMA = 'your_db' 
                       GROUP BY TABLE_NAME;
                      

                      这就是你所需要的。

                      【讨论】:

                      • 生成估计的表行 - 与“mysql_num_rows($tableresult)”比较
                      • 这实际上是最好的答案!从 mysql cli 执行也更简单:mysql&gt; SELECT TABLE_NAME,SUM(TABLE_ROWS) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ngramsdb' GROUP BY TABLE_NAME;
                      【解决方案16】:

                      这就是我使用 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.";
                      

                      【讨论】:

                      • 如果您将忽略数据,为什么不使用 count(*)?
                      【解决方案17】:

                      如果您想要确切的数字,请使用以下 ruby​​ 脚本。你需要 Ruby 和 RubyGems。

                      安装以下 Gems:

                      $> 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.
                      

                      【讨论】:

                        【解决方案18】:

                        如果你使用数据库 information_schema,你可以使用这个 mysql 代码(where 部分使查询不显示行为空值的表):

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

                        【讨论】:

                          【解决方案19】:

                          您可能可以将一些东西与Tables table 放在一起。我从来没有做过,但它看起来有一列用于 TABLE_ROWS 和一列用于 TABLE NAME

                          要获取每个表的行数,您可以使用如下查询:

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

                          【讨论】:

                          • 还有其他方法可以获取 table_row 和 table_name 吗?因为我想要准确的结果而不是粗略的估计。谢谢。
                          • 正如 kuranl 提到的,这只是一个估计值,运行几次后可能会返回不同的结果
                          • 每次运行此查询时,至少有 ~250 条记录的表似乎报告的行数不同。
                          • 哎呀...希望我能事先看到“估计”这个词...就像昨天一样!不应该拒绝回答吗?由于 OP 没有要求“估计”,认为他可能想要估计似乎很愚蠢。 “估计”可以避免像我这样的栗色人错过“估计”吗?
                          猜你喜欢
                          • 2011-06-17
                          • 2022-08-05
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2014-02-25
                          • 2011-07-16
                          相关资源
                          最近更新 更多