#### 13.7.3.1 ANALYZE TABLE Statement

[]()

```
ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name [, tbl_name] ...

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name
    UPDATE HISTOGRAM ON col_name [, col_name] ...
        [WITH N BUCKETS]

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name
    DROP HISTOGRAM ON col_name [, col_name] ...
```

[`ANALYZE TABLE`](analyze-table.html) generates table statistics:

* [`ANALYZE TABLE`](analyze-table.html) without either `HISTOGRAM` clause performs a key distribution analysis and stores the distribution for the named table or tables. For `MyISAM` tables, [`ANALYZE TABLE`](analyze-table.html) for key distribution analysis is equivalent to using [**myisamchk --analyze**](myisamchk.html).

* [`ANALYZE TABLE`](analyze-table.html) with the `UPDATE HISTOGRAM` clause generates histogram statistics for the named table columns and stores them in the data dictionary. Only one table name is permitted for this syntax.

* [`ANALYZE TABLE`](analyze-table.html) with the `DROP HISTOGRAM` clause removes histogram statistics for the named table columns from the data dictionary. Only one table name is permitted for this syntax.

 This statement requires [`SELECT`](privileges-provided.html#priv_select) and [`INSERT`](privileges-provided.html#priv_insert) privileges for the table.

[`ANALYZE TABLE`](analyze-table.html) works with `InnoDB`, `NDB`, and `MyISAM` tables. It does not work with views.

 If the [`innodb_read_only`](innodb-parameters.html#sysvar_innodb_read_only) system variable is enabled, [`ANALYZE TABLE`](analyze-table.html) may fail because it cannot update statistics tables in the data dictionary, which use `InnoDB`. For [`ANALYZE TABLE`](analyze-table.html) operations that update the key distribution, failure may occur even if the operation updates the table itself (for example, if it is a `MyISAM` table). To obtain the updated distribution statistics, set [`information_schema_stats_expiry=0`](server-system-variables.html#sysvar_information_schema_stats_expiry).

[`ANALYZE TABLE`](analyze-table.html) is supported for partitioned tables, and you can use `ALTER TABLE ... ANALYZE PARTITION` to analyze one or more partitions; for more information, see [Section 13.1.9, “ALTER TABLE Statement”](alter-table.html), and [Section 24.3.4, “Maintenance of Partitions”](partitioning-maintenance.html).

 During the analysis, the table is locked with a read lock for `InnoDB` and `MyISAM`.

[`ANALYZE TABLE`](analyze-table.html) removes the table from the table definition cache, which requires a flush lock. If there are long running statements or transactions still using the table, subsequent statements and transactions must wait for those operations to finish before the flush lock is released. Because [`ANALYZE TABLE`](analyze-table.html) itself typically finishes quickly, it may not be apparent that delayed transactions or statements involving the same table are due to the remaining flush lock.

 By default, the server writes [`ANALYZE TABLE`](analyze-table.html) statements to the binary log so that they replicate to replicas. To suppress logging, specify the optional `NO_WRITE_TO_BINLOG` keyword or its alias `LOCAL`.

* [ANALYZE TABLE Output](analyze-table.html#analyze-table-output)

* [Key Distribution Analysis](analyze-table.html#analyze-table-key-distribution-analysis)

* [Histogram Statistics Analysis](analyze-table.html#analyze-table-histogram-statistics-analysis)

* [Other Considerations](analyze-table.html#analyze-table-other-considerations)

##### ANALYZE TABLE Output

[`ANALYZE TABLE`](analyze-table.html) returns a result set with the columns shown in the following table.

|  Column  |                     Value                     |
|----------|-----------------------------------------------|
| `Table`  |                The table name                 |
|   `Op`   |           `analyze` or `histogram`            |
|`Msg_type`|`status`, `error`, `info`, `note`, or `warning`|
|`Msg_text`|           An informational message            |

##### Key Distribution Analysis

[`ANALYZE TABLE`](analyze-table.html) without either `HISTOGRAM` clause performs a key distribution analysis and stores the distribution for the table or tables. Any existing histogram statistics remain unaffected.

 If the table has not changed since the last key distribution analysis, the table is not analyzed again.

 MySQL uses the stored key distribution to decide the order in which tables should be joined for joins on something other than a constant. In addition, key distributions can be used when deciding which indexes to use for a specific table within a query.

 To check the stored key distribution cardinality, use the [`SHOW INDEX`](show-index.html) statement or the `INFORMATION_SCHEMA` [`STATISTICS`](information-schema-statistics-table.html) table. See [Section 13.7.7.22, “SHOW INDEX Statement”](show-index.html), and [Section 26.3.34, “The INFORMATION\_SCHEMA STATISTICS Table”](information-schema-statistics-table.html).

 For `InnoDB` tables, [`ANALYZE TABLE`](analyze-table.html) determines index cardinality by performing random dives on each of the index trees and updating index cardinality estimates accordingly. Because these are only estimates, repeated runs of [`ANALYZE TABLE`](analyze-table.html) could produce different numbers. This makes [`ANALYZE TABLE`](analyze-table.html) fast on `InnoDB` tables but not 100% accurate because it does not take all rows into account.

 You can make the [statistics](glossary.html#glos_statistics) collected by [`ANALYZE TABLE`](analyze-table.html) more precise and more stable by enabling [`innodb_stats_persistent`](innodb-parameters.html#sysvar_innodb_stats_persistent), as explained in [Section 15.8.10.1, “Configuring Persistent Optimizer Statistics Parameters”](innodb-persistent-stats.html). When [`innodb_stats_persistent`](innodb-parameters.html#sysvar_innodb_stats_persistent) is enabled, it is important to run [`ANALYZE TABLE`](analyze-table.html) after major changes to index column data, as statistics are not recalculated periodically (such as after a server restart).

 If [`innodb_stats_persistent`](innodb-parameters.html#sysvar_innodb_stats_persistent) is enabled, you can change the number of random dives by modifying the [`innodb_stats_persistent_sample_pages`](innodb-parameters.html#sysvar_innodb_stats_persistent_sample_pages) system variable. If [`innodb_stats_persistent`](innodb-parameters.html#sysvar_innodb_stats_persistent) is disabled, modify [`innodb_stats_transient_sample_pages`](innodb-parameters.html#sysvar_innodb_stats_transient_sample_pages) instead.

 For more information about key distribution analysis in `InnoDB`, see [Section 15.8.10.1, “Configuring Persistent Optimizer Statistics Parameters”](innodb-persistent-stats.html), and [Section 15.8.10.3, “Estimating ANALYZE TABLE Complexity for InnoDB Tables”](innodb-analyze-table-complexity.html).

 MySQL uses index cardinality estimates in join optimization. If a join is not optimized in the right way, try running [`ANALYZE TABLE`](analyze-table.html). In the few cases that [`ANALYZE TABLE`](analyze-table.html) does not produce values good enough for your particular tables, you can use `FORCE INDEX` with your queries to force the use of a particular index, or set the [`max_seeks_for_key`](server-system-variables.html#sysvar_max_seeks_for_key) system variable to ensure that MySQL prefers index lookups over table scans. See [Section B.3.5, “Optimizer-Related Issues”](optimizer-issues.html).

##### Histogram Statistics Analysis

[`ANALYZE TABLE`](analyze-table.html) with the `HISTOGRAM` clause enables management of histogram statistics for table column values. For information about histogram statistics, see [Section 8.9.6, “Optimizer Statistics”](optimizer-statistics.html).

 These histogram operations are available:

* [`ANALYZE TABLE`](analyze-table.html) with an `UPDATE HISTOGRAM` clause generates histogram statistics for the named table columns and stores them in the data dictionary. Only one table name is permitted for this syntax.

   The optional `WITH *`N`* BUCKETS` clauses specifies the number of buckets for the histogram. The value of *`N`* must be an integer in the range from 1 to 1024. If this clause is omitted, the number of buckets is 100.

* [`ANALYZE TABLE`](analyze-table.html) with a `DROP HISTOGRAM` clause removes histogram statistics for the named table columns from the data dictionary. Only one table name is permitted for this syntax.

 Stored histogram management statements affect only the named columns. Consider these statements:

```
ANALYZE TABLE t UPDATE HISTOGRAM ON c1, c2, c3 WITH 10 BUCKETS;
ANALYZE TABLE t UPDATE HISTOGRAM ON c1, c3 WITH 10 BUCKETS;
ANALYZE TABLE t DROP HISTOGRAM ON c2;
```

 The first statement updates the histograms for columns `c1`, `c2`, and `c3`, replacing any existing histograms for those columns. The second statement updates the histograms for `c1` and `c3`, leaving the `c2` histogram unaffected. The third statement removes the histogram for `c2`, leaving those for `c1` and `c3` unaffected.

 Histogram generation is not supported for encrypted tables (to avoid exposing data in the statistics) or `TEMPORARY` tables.

 Histogram generation applies to columns of all data types except geometry types (spatial data) and [`JSON`](json.html).

 Histograms can be generated for stored and virtual generated columns.

 Histograms cannot be generated for columns that are covered by single-column unique indexes.

 Histogram management statements attempt to perform as much of the requested operation as possible, and report diagnostic messages for the remainder. For example, if an `UPDATE HISTOGRAM` statement names multiple columns, but some of them do not exist or have an unsupported data type, histograms are generated for the other columns, and messages are produced for the invalid columns.

 Histograms are affected by these DDL statements:

* [`DROP TABLE`](drop-table.html) removes histograms for columns in the dropped table.

* [`DROP DATABASE`](drop-database.html) removes histograms for any table in the dropped database because the statement drops all tables in the database.

* [`RENAME TABLE`](rename-table.html) does not remove histograms. Instead, it renames histograms for the renamed table to be associated with the new table name.

* [`ALTER TABLE`](alter-table.html) statements that remove or modify a column remove histograms for that column.

* [`ALTER TABLE ... CONVERT TO CHARACTER SET`](alter-table.html) removes histograms for character columns because they are affected by the change of character set. Histograms for noncharacter columns remain unaffected.

 The [`histogram_generation_max_mem_size`](server-system-variables.html#sysvar_histogram_generation_max_mem_size) system variable controls the maximum amount of memory available for histogram generation. The global and session values may be set at runtime.

 Changing the global [`histogram_generation_max_mem_size`](server-system-variables.html#sysvar_histogram_generation_max_mem_size) value requires privileges sufficient to set global system variables. Changing the session [`histogram_generation_max_mem_size`](server-system-variables.html#sysvar_histogram_generation_max_mem_size) value requires privileges sufficient to set restricted session system variables. See [Section 5.1.9.1, “System Variable Privileges”](system-variable-privileges.html).

 If the estimated amount of data to be read into memory for histogram generation exceeds the limit defined by [`histogram_generation_max_mem_size`](server-system-variables.html#sysvar_histogram_generation_max_mem_size), MySQL samples the data rather than reading all of it into memory. Sampling is evenly distributed over the entire table. MySQL uses `SYSTEM` sampling, which is a page-level sampling method.

 The `sampling-rate` value in the `HISTOGRAM` column of [`INFORMATION_SCHEMA.COLUMN_STATISTICS`](information-schema-column-statistics-table.html) table can be queried to determine the fraction of data that was sampled to create the histogram. The `sampling-rate` is a number between 0.0 and 1.0. A value of 1 means that all of the data was read (no sampling).

 The following example demonstrates sampling. To ensure that the amount of data exceeds the [`histogram_generation_max_mem_size`](server-system-variables.html#sysvar_histogram_generation_max_mem_size) limit for the purpose of the example, the limit is set to a low value (2000000 bytes) prior to generating histogram statistics for the `birth_date` column of the `employees` table.

```
mysql> SET histogram_generation_max_mem_size = 2000000;

mysql> USE employees;

mysql> ANALYZE TABLE employees UPDATE HISTOGRAM ON birth_date WITH 16 BUCKETS\G
*************************** 1. row ***************************
   Table: employees.employees
      Op: histogram
Msg_type: status
Msg_text: Histogram statistics created for column 'birth_date'.

mysql> SELECT HISTOGRAM->>'$."sampling-rate"'
       FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
       WHERE TABLE_NAME = "employees"
       AND COLUMN_NAME = "birth_date";
+---------------------------------+
| HISTOGRAM->>'$."sampling-rate"' |
+---------------------------------+
| 0.0491431208869665              |
+---------------------------------+
```

 A `sampling-rate` value of 0.0491431208869665 means that approximately 4.9% of the data from the `birth_date` column was read into memory for generating histogram statistics.

 As of MySQL 8.0.19, the `InnoDB` storage engine provides its own sampling implementation for data stored in `InnoDB` tables. The default sampling implementation used by MySQL when storage engines do not provide their own requires a full table scan, which is costly for large tables. The `InnoDB` sampling implementation improves sampling performance by avoiding full table scans.

 The `sampled_pages_read` and `sampled_pages_skipped` [`INNODB_METRICS`](information-schema-innodb-metrics-table.html) counters can be used to monitor sampling of `InnoDB` data pages. (For general [`INNODB_METRICS`](information-schema-innodb-metrics-table.html) counter usage information, see [Section 26.4.21, “The INFORMATION\_SCHEMA INNODB\_METRICS Table”](information-schema-innodb-metrics-table.html).)

 The following example demonstrates sampling counter usage, which requires enabling the counters prior to generating histogram statistics.

```
mysql> SET GLOBAL innodb_monitor_enable = 'sampled%';

mysql> USE employees;

mysql> ANALYZE TABLE employees UPDATE HISTOGRAM ON birth_date WITH 16 BUCKETS\G
*************************** 1. row ***************************
   Table: employees.employees
      Op: histogram
Msg_type: status
Msg_text: Histogram statistics created for column 'birth_date'.

mysql> USE INFORMATION_SCHEMA;

mysql> SELECT NAME, COUNT FROM INNODB_METRICS WHERE NAME LIKE 'sampled%'\G
*************************** 1. row ***************************
 NAME: sampled_pages_read
COUNT: 43
*************************** 2. row ***************************
 NAME: sampled_pages_skipped
COUNT: 843
```

 This formula approximates a sampling rate based on the sampling counter data:

```
sampling rate = sampled_page_read/(sampled_pages_read + sampled_pages_skipped)
```

 A sampling rate based on sampling counter data is roughly the same as the `sampling-rate` value in the `HISTOGRAM` column of [`INFORMATION_SCHEMA.COLUMN_STATISTICS`](information-schema-column-statistics-table.html) table.

 For information about memory allocations performed for histogram generation, monitor the Performance Schema `memory/sql/histograms` instrument. See [Section 27.12.20.10, “Memory Summary Tables”](performance-schema-memory-summary-tables.html).

##### Other Considerations

`ANALYZE TABLE` clears table statistics from the [`INFORMATION_SCHEMA.INNODB_TABLESTATS`](information-schema-innodb-tablestats-table.html) table and sets the `STATS_INITIALIZED` column to `Uninitialized`. Statistics are collected again the next time the table is accessed.

