#### 8.4.3.1 MySQL 如何打开和关闭表

[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)

当你执行一个[**mysql管理员状态**](mysqladmin.html)命令，您应该会看到如下内容：

```
Uptime: 426 Running threads: 1 Questions: 11082
Reloads: 1 Open tables: 12
```

这`打开表`如果您的表少于 12 个，那么 12 的值可能会有些令人费解。

MySQL 是多线程的，因此可能有许多客户端同时对给定表发出查询。为了尽量减少在同一个表上具有不同状态的多个客户端会话的问题，该表由每个并发会话独立打开。这会使用额外的内存，但通常会提高性能。和`MyISAM`表，每个打开表的客户端的数据文件都需要一个额外的文件描述符。（相比之下，索引文件描述符在所有会话之间共享。）

这[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)和[`最大连接数`](server-system-variables.html#sysvar_max_connections)系统变量会影响服务器保持打开的最大文件数。如果您增加其中一个或两个值，您可能会遇到操作系统对每个进程打开文件描述符的数量施加的限制。许多操作系统允许您增加打开文件的限制，尽管方法因系统而异。请查阅您的操作系统文档以确定是否可以增加限制以及如何增加限制。

[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)与[`最大连接数`](server-system-variables.html#sysvar_max_connections).例如，对于 200 个并发运行连接，指定表缓存大小至少为`200 * *`ñ`*`， 在哪里*`ñ`*是您执行的任何查询中每个连接的最大表数。您还必须为临时表和文件保留一些额外的文件描述符。

确保您的操作系统可以处理由[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)环境。如果[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)设置得太高，MySQL 可能会用完文件描述符并出现拒绝连接或无法执行查询等症状。

还要考虑到`MyISAM`存储引擎需要两个文件描述符用于每个唯一的打开表。要增加 MySQL 可用的文件描述符的数量，请设置[`open_files_limit`](server-system-variables.html#sysvar_open_files_limit)系统变量。看[第 B.3.2.16 节，“找不到文件和类似错误”](not-enough-file-handles.html).

打开表的缓存保持在[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)条目。服务器在启动时自动调整缓存大小。要显式设置大小，请设置[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)启动时的系统变量。MySQL 可能会暂时打开比这更多的表来执行查询，如本节后面所述。

MySQL 在以下情况下关闭未使用的表并将其从表缓存中删除：

-   当缓存已满并且线程尝试打开不在缓存中的表时。

-   当缓存包含超过[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)缓存中的条目和表不再被任何线程使用。

-   发生表刷新操作时。当有人发出[`同花顺表`](flush.html#flush-tables)语句或执行[**mysqladmin 刷新表**](mysqladmin.html)要么[**mysqladmin 刷新**](mysqladmin.html)命令。

    当表缓存填满时，服务器使用以下过程来定位要使用的缓存条目：

-   当前未使用的表被释放，从最近最少使用的表开始。

-   如果必须打开一个新表，但缓存已满，无法释放任何表，则根据需要临时扩展缓存。当缓存处于临时扩展状态并且表从使用状态变为未使用状态时，表将关闭并从缓存中释放。

    一种`MyISAM`为每个并发访问打开表。这意味着如果两个线程访问同一个表或一个线程在同一个查询中访问该表两次（例如，通过将表连接到自身），则需要打开表两次。每个并发打开都需要表缓存中的一个条目。任何第一次打开`MyISAM`table 有两个文件描述符：一个用于数据文件，一个用于索引文件。表的每一次额外使用只需要一个数据文件的文件描述符。索引文件描述符在所有线程之间共享。

    如果您要使用`处理程序 *`tbl_name`* 打开`语句，为线程分配一个专用的表对象。这个表对象不被其他线程共享，直到线程调用才关闭`处理程序 *`tbl_name`* 关闭`或线程终止。发生这种情况时，表会被放回表缓存中（如果缓存未满）。看[第 13.2.4 节，“处理程序语句”](handler.html).

    要确定您的表缓存是否太小，请检查[`已打开的_tables`](server-status-variables.html#statvar_Opened_tables)status 变量，表示服务器启动后的开表操作次数：


```
mysql> SHOW GLOBAL STATUS LIKE 'Opened_tables';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Opened_tables | 2741  |
+---------------+-------+
```

如果该值非常大或快速增加，即使您没有发出很多[`同花顺表`](flush.html#flush-tables)声明，增加[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)服务器启动时的值。
