MySQL表如何打开? table_definition_cache,table_open_cache,.frm文件和数据字典:它们如何相关?

发布于 2025-01-31 17:39:03 字数 3427 浏览 4 评论 0原文

MySQL版本:5.7机器:Ubuntu 20.04

最近,我们正在分析增加模式中表格数量时可能发生的性能问题。在此期间,我们遇到了对性能产生影响的4个系统变量: table_open_cache open_files_limit table> table_definition_cache 字典内存分配的显示引擎Innodb状态

这是我们所知道的:

  1. table_open_cache :可以在所有会话中同时打开的最大表。
  2. open_files_limit :可以在MySQLD进程中打开的最大文件数量。
  3. table_definition_cache :可以将元数据存储在内存中的表的最大数量,而无需使用文件描述符来读取.frm文件。
  4. 分配的字典记忆:InnodB字典中分配的内存量。没有限制,它不断增加。

考虑到这些信息,我们决定在架构中创建100,000个表,并使用select * select *从tablename命令中读取这些表。

这是我们到达的代码和统计信息:

int num = 1;                
long currTime= System.currentTimeMillis();
for(int i=1;i<=100000;i++)
{
    String tableName = table + i;
    st.executeQuery("select * from " + tableName + "");
    if(i%5000==0)
    {
        printDictMemory(st,num++);
        long diff= System.currentTimeMillis()-currTime;
        LOGGER.log(Level.INFO,i +"tables. "+diff+"ms");
        currTime=System.currentTimeMillis();
    }               
}

printDictMemory()方法运行显示引擎Innodb状态命令并打印当时分配的字典内存。

统计:

系统变量: table_open_cache = 2000, open_files_limit = 5000, table> table> table_definition_cache = 1400

tables  time(ms)    Dictionary memory
    5000    8228ms  105886810
    10000   9008ms  168551811
    15000   9385ms  231221811
    20000   8181ms  174365726
    25000   7376ms  237035726
    30000   6491ms  299705726
    35000   6215ms  362375726
    40000   7087ms  425045726
    45000   6422ms  276819109
    50000   6216ms  339489109
    55000   6720ms  402159109
    60000   7691ms  464829109
    65000   8225ms  527499109
    70000   6128ms  590169109
    75000   6359ms  377517265
    80000   6570ms  440187265
    85000   7913ms  502857265
    90000   9245ms  565527265
    95000   9490ms  352261255
    100000  6202ms  414931256

在此过程中,文件描述符在此过程中的数量不超过2030。

因此,以下是我需要答案的问题:

  1. 为什么字典记忆不会不断增加?
  2. 当字典内存降低大小时发生了什么?
  3. 我通过设置 table_open_cache = 3000 来获取统计数据。但是,文件描述符数量仍在2020年至2030年。为什么文件描述符的数字不增加?
  4. 我们知道,在每个文件表空间中,.frm文件包含table_definition,并且.ibd文件包含表数据。在/proc/pid/fd中,我们从中获取文件描述符的位置。在这里,即使是第一次阅读表,也只读取.ibd文件。列出了否.FRM文件。为什么?
  5. 最后,这是我们认为打开MySQL表时发生的事情:

服务器首先检查打开的表是否小于 table_open_cache 变量的值。如果不是这样,MySQL使用LRU算法来删除最近使用的表格。现在,当读取表格时,InnoDB引擎是否存在表词字典。是否存在表。如果没有,它将检查服务器层中的 table_definition_cache 。如果它在Table_defintion_cache中不存在,则MySQL使用文件描述符来读取.frm,然后使用.ibd文件。然后,它将表定义添加到服务器层中的 table_definition_cache 以及InnoDB存储引擎层中的数据字典。因此,下次需要阅读表时,InnoDB可以简单地从数据字典缓存中获取表定义。

以上流程正确吗?如果没有,MySQL如何打开桌子?请分享您的知识。

编辑:

wrt Wilson的评论,以下是以下统计数据:

全球变量和状态最初:

“在此处输入图像描述”

stats: <

< < a href =“ https://i.sstatic.net/pajoo.png” rel =“ nofollow noreferrer”>

感谢您的耐心配合。肯定会感谢您的答案。

MySQL version: 5.7 Machine: Ubuntu 20.04

Recently, we were analysing the performance issues that can occur when increasing the number of tables in a schema. And during this, we came across 4 system variables that have impact on the performance: table_open_cache, open_files_limit, table_definition_cache and the Dictionary memory allocated from SHOW ENGINE INNODB STATUS

Here's what we know:

  1. table_open_cache: The maximum number of tables that can be open concurrently across all sessions.
  2. open_files_limit: Maximum number of files that can be open in the mysqld process.
  3. table_definition_cache: The maximum number of tables whose metadata can be stored in memory, without having to use file descriptors to read the .frm files.
  4. Dictionary Memory Allocated: The amount of memory that is allocated in the innodb dictionary. There is no limit and it keeps increasing.

With these information in mind, we decided to create 100,000 tables in a schema and run a loop to read these tables using the SELECT * FROM tablename command.

Here is the code and the stats we arrived at:

int num = 1;                
long currTime= System.currentTimeMillis();
for(int i=1;i<=100000;i++)
{
    String tableName = table + i;
    st.executeQuery("select * from " + tableName + "");
    if(i%5000==0)
    {
        printDictMemory(st,num++);
        long diff= System.currentTimeMillis()-currTime;
        LOGGER.log(Level.INFO,i +"tables. "+diff+"ms");
        currTime=System.currentTimeMillis();
    }               
}

The printDictMemory() method runs the SHOW ENGINE INNODB STATUS command and prints the dictionary memory allocated at that time.

Stats:

System variables: table_open_cache=2000, open_files_limit=5000, table_definition_cache=1400

tables  time(ms)    Dictionary memory
    5000    8228ms  105886810
    10000   9008ms  168551811
    15000   9385ms  231221811
    20000   8181ms  174365726
    25000   7376ms  237035726
    30000   6491ms  299705726
    35000   6215ms  362375726
    40000   7087ms  425045726
    45000   6422ms  276819109
    50000   6216ms  339489109
    55000   6720ms  402159109
    60000   7691ms  464829109
    65000   8225ms  527499109
    70000   6128ms  590169109
    75000   6359ms  377517265
    80000   6570ms  440187265
    85000   7913ms  502857265
    90000   9245ms  565527265
    95000   9490ms  352261255
    100000  6202ms  414931256

The file descriptors count during the process did not go beyond 2030.

So, here are the questions that I need answers for:

  1. Why is the Dictionary memory not constantly increasing?
  2. What is happening when the Dictionary memory reduces in size?
  3. I took stats by setting the table_open_cache=3000. But still, the file descriptors count stayed at 2020-2030. Why are the file descriptors not increasing in number?
  4. We know that, in a File-per-Table tablespace, .frm files contain the table_definition and the .ibd files contain the table data. In the /proc/PID/fd is where we took the File descriptor count from. Here, even while reading the table for the first time, only .ibd files were read. No .frm files were listed. Why?
  5. Finally, Here's what we think happens when we open a MySQL table:

The server first checks if the number of tables opened is less than the value of the table_open_cache variable. If it's not, MySQL uses an LRU algorithm to remove the least recently used table. Now, when a table is read, the InnoDB engine checks the Data Dictionary if the table definition is present or not. If not, it checks the table_definition_cache in the server layer. If it's not present in the table_defintion_cache, MySQL uses File Descriptors to read the .frm and then the .ibd files. It then adds the table definition to the table_definition_cache in the server layer and also to the Data Dictionary in the InnoDB storage engine layer. So, next time when the table needs to be read, InnoDB can simply get the table definition from the Data Dictionary cache.

Is the above flow correct? If not, How does MySQL open the tables? Please share your knowledge on the same.

EDIT:

w.r.t Wilson's comment, here are the below stats:

Global VARIABLES and STATUS initially:

enter image description here

Stats:

enter image description here

Thank you for the patience. Would definitely appreciate your answers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

弥繁 2025-02-07 17:39:03

(不是直接的答案,但相关。)

我可以建议statustable_open_cache_hits and code> _misses 对计算误差/秒有用(使用正常时间)和错过百分比。这些公式提供了有关是否正确设置table_open_cache的线索。 las,它没有说要增加或减少该设置多少。

您可能会再次进行实验,同时观看

Table_open_cache_hits / Uptime
Table_open_cache_misses / (Table_open_cache_hits + Table_open_cache_misses)

我“推荐”后者的3%以下。 (这是我在查看变量status时进行的几百个检查之一。

(Not a direct answer, but related.)

May I suggest that the STATUS values Table_open_cache_hits and _misses are useful for computing misses/second (using Uptime) and percentage of misses. These formulas give clues as to whether table_open_cache is set properly. Alas, it does not say how much to increase or decrease that setting.

You might run your experiment again, while watching

Table_open_cache_hits / Uptime
Table_open_cache_misses / (Table_open_cache_hits + Table_open_cache_misses)

I "recommend" that the latter be kept under 3%. (This is one of a few hundred checks I make when reviewing VARIABLES and STATUS for a system.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文