`
sogotobj
  • 浏览: 619223 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

改进MySQL的table_cache

 
阅读更多

以下为本人在工作中的碎碎念,记录的比较凌乱……

........................................................................

在mysql里面有一个参数table_cache,当设置过大时,会产生明显的效率下降。这是因为扫描open_cache哈希表时,使用的线性扫描,时间复杂度为O(n),mysql的bug list上有人提供了一个patch(http://bugs.mysql.com/bug.php?id=33948),可以把时间降到o(1),其基本思想是为table实例增加三个指针,来维护一个空闲链表。


首先,我们分析一下mysql在打开一个表时如何工作:


在mysql里,table_cache是一个比较重要的参数。由于多线程机制,每个线程独自打开自己需要的标的文件描述符,而不是共享已经打开的。




1. table_cache key (见create_table_def_key)
在内存里,table cache使用hash表来存储,key为 database_name\0table_name\0+(可选的,用于临时表)

这里对于临时表会做特殊处理,需要增加额外的信息来保证临时表在slave端是唯一的
增加8个字节:前4个字节为master thread id,后4个字节为slavb


2.打开表时候的处理:open_table


***************
必要的检查:线程栈是否足够,thd是否被kill
**************
全局锁:lock_open
*************************
首先判断是否是临时表
*************************
这里有一段很有意思的逻辑,当需要打开表时,总是先从临时表链表中查找表。也就是说,当存在一个与实际表同名的临时表时,会总是操作临时表
if (!table_list->skip_temporary)
{
for (table= thd->temporary_tables; table ; table=table->next)
{


**********************************************
非临时表,且处于pre-locked 或 lock_tables mode(thd->locked_tables || thd->prelocked_mode)
即该线程已经打开或锁定了一些表,从thd->open_tables里查询,当不存在时,返回error
**********************************************
if (thd->locked_tables || thd->prelocked_mode)
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
for (table=thd->open_tables; table ; table=table->next)
{



*******************************************************
正常情况:
1. 首先尝试从table cache中取table
2. 当找到的TABLE实例是nam-locked的,或者一些线程正在flush tables,我们需要等待,直到锁释放
3. 如果不存在这样的TABLE,我们需要创建TABLE,并将其加入到cache中
!这些操作都需要全局锁:LOCK_open,来保护table cache和磁盘上的表定义
*******************************************************

如果这是该query打开的第一个表:设置thd->version = refresh_version,这样,当我们打开剩余表的过程中,如果 version发生了变化,则需要back off,关闭所有已经打开的并重新打开表
目前refresh_version只会被FLUSH TABLES命令改变

if (thd->handler_tables)
mysql_ha_flush(thd); //刷新(关闭并标记为re-open)所有需要reopen的表


查询table cache的过程:

for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length, //基于同一个key来查找hash表
&state);
table && table->in_use ;
table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,
&state))
{

**********************************
flush tables marked for flush.
Normally, table->s->version contains the value of
refresh_version from the moment when this table was
(re-)opened and added to the cache.
If since then we did (or just started) FLUSH TABLES
statement, refresh_version has been increased.
For "name-locked" TABLE instances, table->s->version is set
to 0 (see lock_table_name for details).
In case there is a pending FLUSH TABLES or a name lock, we
need to back off and re-start opening tables.
If we do not back off now, we may dead lock in case of lock
order mismatch with some other thread:
c1: name lock t1; -- sort of exclusive lock
c2: open t2; -- sort of shared lock
c1: name lock t2; -- blocks
c2: open t1; -- blocks
*********************************

if (table->needs_reopen_or_name_lock()) //Is this instance of the table should be reopen or represents a name-lock?
{}

}

if (table)
************
从unused_tables链表中移除刚找到的table
************
else
***********
创建一个新的table实例,并插入到open cache中
***********
while (open_cache.records > table_cache_size && unused_tables) //当cache满时,从中释放未使用的TABLE实例
hash_delete(&open_cache,(uchar*) unused_tables);

if (table_list->create) //创建一个新表
{

*******
检查表是否存在:check_if_table_exists
*******
在table cache的hash中创建一个placeholder(占位符):table_cache_insert_placeholder
将占位符链到open tables list上:
table->open_placeholder= 1;
table->next= thd->open_tables;
thd->open_tables= table;

return table
}

创建一个新的table实例
分配内存table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))

error= open_unireg_entry(thd, table, table_list, alias, key, key_length,
mem_root, (flags & OPEN_VIEW_NO_PARSE));


如果是视图 or error < 0 释放内存,返回;


my_hash_insert(&open_cache,(uchar*) table)


------------------------------------------------

patch:http://bugs.mysql.com/bug.php?id=33948
增加3个指针:
hash_head:
hash_prev: always point to unused table cached items
hash_next: always point to used table cached items

修改的函数:

free_cache_entry //释放一个表的内存。
close_thread_table //move one table to free list
reopen_name_locked_table //重新打开表,保持链表结构
table_cache_insert_placeholder
open_table
------------------------------------------------------------------------
总结:

增加了三个指针:
hash_head:
hash_prev:
hash_next:

!.............................!head!.........................!

head的左边为空闲item链表
head的右边为占用的item链表
所有item通过hash_prev和hash_next进行双向指针
右边的item的hash_head指向head


操作链表:
1)插入新空闲item:在head节点前加入
2)插入新的被占用item:在head后面加入
3)从链表中删除item:
---若该item为head,修改head右侧的item的hash_head指向head->next
---否则,直接删除item,并释放内存。。

查询空闲节点:
1) 找到head
2) 检测head是否in_use,为False则table = head, true则找到table = head->prev
3)当table 不为NULL时,表示找到一个item,将其插入到head右侧
3) table依旧为NULL---->创建新item,将其插入到head右侧


------------------------------
转载请注明:印风













分享到:
评论

相关推荐

    MySQL thread_cache和table_cache详解

    THREAD_CACHE MySQL里面为了提高客户端请求创建连接过程的性能,提供了一个连接池也就是 Thread_Cache池,将空闲的连接线程放在连接池中,而不是立即销毁.这样的好处就是,当又有一个新的请求的时候,mysql不会立即去创建...

    Mysql优化调优中两个重要参数table_cache和key_buffer

    本文根据作者的一点经验,讨论了Mysql服务器优化中两个非常重要的参数,分别是table_cache,key_buffer_size。 table_cache指示表高速缓存的大小。当Mysql访问一个表时,如果在Mysql表缓冲区中还有空间,那么这个表...

    MySQL性能优化之table_cache配置参数浅析

    table_cache是一个非常重要的MySQL性能参数,它在5.1.3之后的版本中叫做table_open_cache。table_cache主要用于设置table高速缓存的数量。由于每个客户端连接都会至少访问一个表,因此此参数的值与max_connections...

    MySQL 5.6下table_open_cache参数优化合理配置详解

    table_cache是一个非常重要的MySQL性能参数,它在5.1.3之后的版本中叫做table_open_cache。table_cache主要用于设置table高速缓存的数量。由于每个客户端连接都会至少访问一个表,因此此参数的值与max_connections...

    mysql提示Changed limits: max_open_files: 2048 max_connections: 1910 table_cache: 64的解决

    在windows下安装Mysql系统日志出现max_open_files: 2048 max_connections: 510 table_cache: 764 类似错误是因为 max_connections 最大连接数和max_open_files、table_cache 不匹配。适当的降低max_connections 或...

    MySQL性能优化配置参数之thread_cache和table_cache详解

    主要介绍了MySQL性能优化配置参数之thread_cache和table_cache详解,THREAD_CACHE是Mysql的连接池,table_cache指定表高速缓存的大小,需要的朋友可以参考下

    mysql优化的重要参数 key_buffer_size table_cache

    对于使用Myisam存储引擎来说,主要有key_buffer_size和table_cache两个参数。对于InnoDB引擎来说主要还是以innodb_开始的参数,也很好辨认。 查看MySQL参数,可以使用show variables和show status命令查看,前者查看...

    浅析MySQL内存的使用说明(全局缓存+线程缓存)

    首先我们来看一个公式,MySQL中内存分为全局内存和线程...buffer_size+binlog_cache_size+tmp_table_size)*max_connectionsglobal_buffers=innodb_buffer_pool_size+innodb_additional_mem_pool_size+innodb_log_buf

    MySQL错误ERROR 1615 解决方法

    今天测试合服脚本的时候,遇到一个很奇怪的问题。Mysql报ERROR: ERROR 1615 (HY000): Prepared statement needs to be re-prepared 经过测试,发现不是合服脚本的问题...mysql&gt; set global table_definition_cache=163

    MySQL8.0内存相关参数总结

    也就是:innodb_buffer_pool_size + innodb_log_buffer_size + thread_cache_size +table_open_cache + table_definition_cache +key_buffer_size + max_connections *( thread_stack+ sort_buffer_size+join_...

    可以改善mysql性能的InnoDB配置参数

    而由于InnoDB是一个健壮的事务型存储引擎,已经有10多年的历史,一些重量级的...推荐此参数至少设置为2MB,实际上,是需要根据项目的InnoDB表的数目相应地增加 2.innodb_data_pool_size 此参数类似于MySQL的key_bu

    MySQL的Innodb引擎配置说明.txt

    内容包括: 1.MySQL的Innodb引擎配置 1.如何配置MySQL服务器的最大连接数量 2.如何配置innodb_open_files,table_open_cache,innodb_file_io_threads和innodb_buffer_pool_size,innodb_log_file_size

    php资料库4 防止foeach中变量不是数组

    MySQL优化经验 key_buffer_size,query_cache_size,table_cache.txt bbscon.mht mysql SHOW STATUS 详解_病毒的BLOG_新浪博客.mht MYSQL系统优化与系统设置参数的一次调查-(2)_Linux技术文章_Linux_操作系统.mht ...

    MySql减少内存占用的方法详解

    前言 默认设置下,mysql会初始化很大的内存块用于缓存数据库查询数据。 但我的小主机只有640mb的内存,top查询发现他吃了我30% 的内存总量,...table_definition_cache=150 table_open_cache=64 然后 service mysql r

Global site tag (gtag.js) - Google Analytics