How to get the sizes of the tables of a MySQL database?
Asked Answered
J

21

1159

I can run this query to get the sizes of all tables in a MySQL database:

show table status from myDatabaseName;

I would like some help in understanding the results. I am looking for tables with the largest sizes.

Which column should I look at?

Jarrodjarrow answered 8/3, 2012 at 15:30 Comment(3)
What do you mean by size? Number of rows? Bytes taken on disk?Bromism
@Mark i want size on disk is this right method ? # du -sh /mnt/mysql_data/openx/f_scraper_banner_details.MYI 79G /mnt/mysql_data/openx/f_scraper_banner_details.MYICorollaceous
Related, if it's of interest, I wrote a Describe All Tables in this Answer.Gunar
E
2378

You can use this query to show the size of a table (although you need to substitute the variables first):

SELECT 
    table_name AS `Table`, 
    round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` 
FROM information_schema.TABLES 
WHERE table_schema = "$DB_NAME"
    AND table_name = "$TABLE_NAME";

or this query to list the size of every table in every database, largest first:

SELECT 
     table_schema as `Database`, 
     table_name AS `Table`, 
     round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` 
FROM information_schema.TABLES 
ORDER BY (data_length + index_length) DESC;
Exaggerated answered 8/3, 2012 at 15:34 Comment(16)
Thank you, its working just fine, though I am not sure it takes Blobs in consideration.Conferee
Note, you can also use "IN" to specify multiple tables, e.g AND table_name IN ('table_1', 'table_2', 'table_3');Kassiekassity
AFAICT, this will only count the lengths of static size fields correctly. How would you count VARCHAR and BLOB types?Isaacson
Hi, I notice that the number produced by this query (the top one at least) doesn't always reflect changes I make in my table; i.e. I add rows and the number stays the same after the change. Is there a way to reliably get this number to update according to the present size of the table?Principe
You're dividing the SUM by 1024 twice to go from bytes to kilobytes and on to megabytes. This assumes a kilobyte comprises 1024 bytes, but Mac OS uses the 'decimal' system, which says 1 kilobyte = 1000 bytes (en.wikipedia.org/wiki/Kilobyte). Shouldn't the SUM therefore not be divided by 1000 twice on these systems, or does MySQL somehow compensate/ignore this?Quarrier
And what if you write a plugin for others and you do not know about their database name $DB_NAME? I can get the database name by SELECT DATABASE() but do not know how to combine this with the query above.Taciturn
@EchtEinfachTV Replace "$DB_NAME" with (SELECT DATABASE())Antoine
@Quarrier At some point the world got confusing and some standards organizations and hardware manufacturers decided that it was better that a kilobyte be defined on the decimal system. The IEC standard now calls the base 2 kilobyte (1024 bytes) a kibibyte (KiB). At any rate, MySQL doesn't know, so if you want IEC decimal kilobytes, divide by 1000.Relaxation
How to make it when there is no access to information_schema DB?Dentate
@Principe You need to run OPTIMIZE TABLE tablename. Then you can get a reliable number.Swallow
Will this work for the InnoDB storage engine? According to mysql doc here - dev.mysql.com/doc/refman/5.7/en/show-table-status.html, the data_length field for that engine contains the size of the clustered index. That won't correctly represent the size of the data. Will it?Reglet
optional where clause to restrict to a DB: where table_schema='mydatabase'Zante
awesome answer, saved me trouble! I used to look at the file sizes on the console, but after migrating to RDS, this is no longer an optionPacheco
Best answer, worked like a treat while other had issues or did not return the expected result. ThanksCohe
It indeed doesn't tell correct size for instance if you have blob fields in the table. LOB pages are stored in external pages so they are not accounted in the clustered index.Afebrile
It is obviously not correct. At least it is wrong for MariaDB on Linux and sbtest database.Nyctophobia
A
135
SELECT TABLE_NAME AS "Table Name", 
table_rows AS "Quant of Rows", ROUND( (
data_length + index_length
) /1024, 2 ) AS "Total Size Kb"
FROM information_schema.TABLES
WHERE information_schema.TABLES.table_schema = 'YOUR SCHEMA NAME/DATABASE NAME HERE'
LIMIT 0 , 30

You can get schema name from "information_schema" -> SCHEMATA table -> "SCHEMA_NAME" column


Additional You can get size of the mysql databases as following.

SELECT table_schema "DB Name", 
Round(Sum(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB" 
FROM   information_schema.tables 
GROUP  BY table_schema
ORDER BY `DB Size in MB` DESC;

Result

DB Name              |      DB Size in MB

mydatabase_wrdp             39.1
information_schema          0.0

You can get additional details in here.

Academe answered 15/9, 2012 at 17:41 Comment(2)
How can it be that with the above query I see database sizes of 200 MB, but on the disk it's like 38 GB! Over 2300 mysql-bin.* files, each about 15.6 MB...?!Bish
@Bish the binlogs are separate from the data files. you could rack up a lot of binlogs with lots of activity, insert/delete etc., while the tables are not taking up a lot. Check your expire_log_days dev.mysql.com/doc/refman/8.0/en/… - you can save space by keeping less binary logsStpeter
H
63
SELECT 
    table_name AS "Table",  
    round(((data_length + index_length) / 1024 / 1024), 2) as size   
FROM information_schema.TABLES  
WHERE table_schema = "YOUR_DATABASE_NAME"  
ORDER BY size DESC; 

This sorts the sizes (DB Size in MB).

Highwayman answered 18/1, 2014 at 15:9 Comment(1)
This helped. As simple as it could be. <3Alishiaalisia
D
47

If you want a query to use currently selected database. simply copy paste this query. (No modification required)

SELECT table_name ,
  round(((data_length + index_length) / 1024 / 1024), 2) as SIZE_MB
FROM information_schema.TABLES
WHERE table_schema = DATABASE() ORDER BY SIZE_MB DESC;
Dit answered 16/2, 2017 at 0:56 Comment(1)
Or even shorter (without subquery): SELECT table_name, round(((data_length + index_length) / 1024 / 1024), 2) SIZE_MB FROM information_schema.TABLES WHERE table_schema=DATABASE() ORDER BY (data_length + index_length) ASC;Alleneallentown
D
35
  • Size of all tables:

    Suppose your database or TABLE_SCHEMA name is "news_alert". Then this query will show the size of all tables in the database.

    SELECT
      TABLE_NAME AS `Table`,
      ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024),2) AS `Size (MB)`
    FROM
      information_schema.TABLES
    WHERE
      TABLE_SCHEMA = "news_alert"
    ORDER BY
      (DATA_LENGTH + INDEX_LENGTH)
    DESC;
    

    Output:

        +---------+-----------+
        | Table   | Size (MB) |
        +---------+-----------+
        | news    |      0.08 |
        | keyword |      0.02 |
        +---------+-----------+
        2 rows in set (0.00 sec)
    
  • For the specific table:

    Suppose your TABLE_NAME is "news". Then SQL query will be-

    SELECT
      TABLE_NAME AS `Table`,
      ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024),2) AS `Size (MB)`
    FROM
      information_schema.TABLES
    WHERE
        TABLE_SCHEMA = "news_alert"
      AND
        TABLE_NAME = "news"
    ORDER BY
      (DATA_LENGTH + INDEX_LENGTH)
    DESC;
    

    Output:

    +-------+-----------+
    | Table | Size (MB) |
    +-------+-----------+
    | news  |      0.08 |
    +-------+-----------+
    1 row in set (0.00 sec)
    
Dashboard answered 10/9, 2017 at 17:54 Comment(0)
P
20

There is an easy way to get many informations using Workbench:

  • Right-click the schema name and click "Schema inspector".

  • In the resulting window you have a number of tabs. The first tab "Info" shows a rough estimate of the database size in MB.

  • The second tab, "Tables", shows Data length and other details for each table.

Phytogenesis answered 27/2, 2015 at 15:29 Comment(2)
I didn't have the 'info' tab on my Mac client v 6.0.9Longdistance
Great!!! In MySQL Workbench there's also a "Table Inspector" for each table. Not properly quick but very handy!Econometrics
P
11

I find the existing answers don't actually give the size of tables on the disk, which is more helpful. This query gives more accurate disk estimate compared to table size based on data_length & index. I had to use this for an AWS RDS instance where you cannot physically examine the disk and check file sizes.

select NAME as TABLENAME,FILE_SIZE/(1024*1024*1024) as ACTUAL_FILE_SIZE_GB
, round(((data_length + index_length) / 1024 / 1024/1024), 2) as REPORTED_TABLE_SIZE_GB 
from INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES s
join INFORMATION_SCHEMA.TABLES t 
on NAME = Concat(table_schema,'/',table_name)
order by FILE_SIZE desc
Paranoiac answered 2/5, 2019 at 9:14 Comment(3)
this should be the answer, for INNODB at least. Just adding up DATA_LENGTH, INDEX_LENGTH & DATA_FREE doesn't get the size on Disk if you have large out-of-row data fields (like blobs). For INNODB you do need to use INNDB_SYS_TABLESPACES.FILE_SIZE to get an accurate read of the on disk size, but you also need PROCESS privilege to select from this table.Poult
If MySQL 8.0, use INNODB_TABLESPACES instead of INNODB_SYS_TABLESPACESManrope
It's extremely useful when you have a ton of blobs inside the database, also it gives correct sizing when calculating black-box AWS RDS. Thank you!Wine
G
8

Try the following shell command (replace DB_NAME with your database name):

mysql -uroot <<<"SELECT table_name AS 'Tables', round(((data_length + index_length) / 1024 / 1024), 2) 'Size in MB' FROM information_schema.TABLES WHERE table_schema = \"DB_NAME\" ORDER BY (data_length + index_length) DESC;" | head

For Drupal/drush solution, check the following example script which will display the biggest tables in use:

#!/bin/sh
DB_NAME=$(drush status --fields=db-name --field-labels=0 | tr -d '\r\n ')
drush sqlq "SELECT table_name AS 'Tables', round(((data_length + index_length) / 1024 / 1024), 2) 'Size in MB' FROM information_schema.TABLES WHERE table_schema = \"${DB_NAME}\" ORDER BY (data_length + index_length) DESC;" | head -n20
Grodno answered 8/5, 2014 at 11:27 Comment(0)
H
7

Heres another way of working this out from using the bash command line.

for i in `mysql -NB -e 'show databases'`; do echo $i; mysql -e "SELECT table_name AS 'Tables', round(((data_length+index_length)/1024/1024),2) 'Size in MB' FROM information_schema.TABLES WHERE table_schema =\"$i\" ORDER BY (data_length + index_length) DESC" ; done
Henotheism answered 10/11, 2014 at 11:6 Comment(0)
K
6

If you are using phpmyadmin then just go to the table structure

e.g.

Space usage
Data    1.5 MiB
Index   0   B
Total   1.5 Mi
Kiss answered 21/3, 2015 at 14:5 Comment(0)
T
5

Adapted from ChapMic's answer to suite my particular need.

Only specify your database name, then sort all the tables in descending order - from LARGEST to SMALLEST table inside selected database. Needs only 1 variable to be replaced = your database name.

SELECT 
table_name AS `Table`, 
round(((data_length + index_length) / 1024 / 1024), 2) AS `size`
FROM information_schema.TABLES 
WHERE table_schema = "YOUR_DATABASE_NAME_HERE"
ORDER BY size DESC;
Telestich answered 31/3, 2017 at 23:16 Comment(0)
H
4

Another way of showing the number of rows and space occupied and ordering by it.

SELECT
     table_schema as `Database`,
     table_name AS `Table`,
     table_rows AS "Quant of Rows",
     round(((data_length + index_length) / 1024 / 1024/ 1024), 2) `Size in GB`
FROM information_schema.TABLES
WHERE table_schema = 'yourDatabaseName'
ORDER BY (data_length + index_length) DESC;  

The only string you have to substitute in this query is "yourDatabaseName".

Hylton answered 13/2, 2017 at 6:6 Comment(0)
G
4

If you have ssh access, you might want to simply try du -hc /var/lib/mysql (or different datadir, as set in your my.cnf) as well.

Gianina answered 17/7, 2017 at 15:54 Comment(1)
Finally an answer that doesn't rely on information_schema. In my case it reported 660MB while the actual size on the filesystem is 1.8GBSilber
Q
3

This should be tested in mysql, not postgresql:

SELECT table_schema, # "DB Name", 
Round(Sum(data_length + index_length) / 1024 / 1024, 1) # "DB Size in MB" 
FROM   information_schema.tables 
GROUP  BY table_schema; 
Quinque answered 4/9, 2018 at 3:8 Comment(1)
While this might answer the authors question, it lacks some explaining words and/or links to documentation. Raw code snippets are not very helpful without some phrases around them. You may also find how to write a good answer very helpful. Please edit your answer - From ReviewUnappealable
Q
2
SELECT TABLE_NAME AS table_name, 
table_rows AS QuantofRows, 
ROUND((data_length + index_length) /1024, 2 ) AS total_size_kb 
FROM information_schema.TABLES
WHERE information_schema.TABLES.table_schema = 'db'
ORDER BY (data_length + index_length) DESC; 

all 2 above is tested on mysql

Quinque answered 4/9, 2018 at 3:11 Comment(0)
W
1

Calculate the total size of the database at the end:

(SELECT 
  table_name AS `Table`, 
  round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` 
  FROM information_schema.TABLES 
  WHERE table_schema = "$DB_NAME"
)
UNION ALL
(SELECT 
  'TOTAL:',
  SUM(round(((data_length + index_length) / 1024 / 1024), 2) )
  FROM information_schema.TABLES 
  WHERE table_schema = "$DB_NAME"
)
Wolver answered 18/7, 2018 at 5:58 Comment(0)
U
1

Replace "DB_NAME" with the name of your database:

SELECT 
    table_schema AS `Database`, 
    table_name AS `Table`, 
    ROUND(((data_length + index_length) / 1024 / 1024)) as `Size in MB` 
FROM information_schema.TABLES `enter code here`
WHERE table_schema = "$DB_NAME"
ORDER BY (data_length + index_length) DESC;
Umbrella answered 18/11, 2020 at 20:11 Comment(1)
I'm not sure why the downvote but I suspect it needs an explaination.Steel
A
1

This is just a note for future reference. All answers are relying on the I_S.TABLES. It doesn't tell correct size for instance if you have blob fields in the table. LOB pages are stored in external pages so they are not accounted in the clustered index. In fact there is a note :

For NDB tables, the output of this statement shows appropriate values for the AVG_ROW_LENGTH and DATA_LENGTH columns, with the exception that BLOB columns are not taken into account.

I found to be true for InnoDB as well.

I have created community Bug for the same.

Afebrile answered 31/3, 2022 at 4:39 Comment(0)
A
1

Try this command: Replace your_database_name with the name of your MySQL database.

SELECT 
    table_name AS `Table`,
    round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB`
FROM information_schema.tables
WHERE table_schema = 'your_database_name'
ORDER BY `Size in MB` DESC;

Arielariela answered 20/2 at 14:21 Comment(0)
U
0

Here we can find the database size from the information_schema.tables default database in MySQL server where we can find metadata of MySql Server databases.

Query for see tables size:

SELECT 
    table_name AS `Table`,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS `Size (MB)`
FROM information_schema.tables
WHERE table_schema = 'your_database_name'
ORDER BY (data_length + index_length) DESC;

Query for see all database size:

SELECT 
    table_schema AS `Database`,
    ROUND(SUM(data_length + index_length) / (1024 * 1024), 2) AS `Size (MB)`
FROM information_schema.tables
WHERE table_schema = 'your_database_name'
GROUP BY table_schema;
Usn answered 16/1 at 10:52 Comment(0)
D
-2

I've made this shell script to keep a track of table size (in bytes and in number of rows)

#!/bin/sh

export MYSQL_PWD=XXXXXXXX
TABLES="table1 table2 table3"

for TABLE in $TABLES;
do
        FILEPATH=/var/lib/mysql/DBNAME/$TABLE.ibd
        TABLESIZE=`wc -c $FILEPATH | awk '{print $1}'`
        #Size in Bytes
        mysql -D scarprd_self -e "INSERT INTO tables_sizes (table_name,table_size,measurement_type) VALUES ('$TABLE', '$TABLESIZE', 'BYTES');"
        #Size in rows
        ROWSCOUNT=$(mysql -D scarprd_self -e "SELECT COUNT(*) AS ROWSCOUNT FROM $TABLE;")
        ROWSCOUNT=${ROWSCOUNT//ROWSCOUNT/}
        mysql -D scarprd_self -e "INSERT INTO tables_sizes (table_name,table_size,measurement_type) VALUES ('$TABLE', '$ROWSCOUNT', 'ROWSCOUNT');"
        mysql -D scarprd_self -e "DELETE FROM tables_sizes WHERE measurement_datetime < TIMESTAMP(DATE_SUB(NOW(), INTERVAL 365 DAY));"
done

It presuppose to have this MySQL table

CREATE TABLE `tables_sizes` (
  `table_name` VARCHAR(128) NOT NULL,
  `table_size` VARCHAR(25) NOT NULL,
  `measurement_type` VARCHAR(10) NOT NULL CHECK (measurement_type IN ('BYTES','ROWSCOUNT')),
  `measurement_datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()
) ENGINE=INNODB DEFAULT CHARSET=utf8
Deuteranopia answered 23/9, 2021 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.