详解mysql的线程、table cache和临时表的优化
一、THREAD_CACHE
MySQL里面为了提高客户端请求创建连接过程的性能,提供了一个连接池也就是 Thread_Cache池,将空闲的连接线程放在连接池中,而不是立即销毁.这样的好处就是,当又有一个新的请求的时候,mysql不会立即去创建连接 线程,而是先去Thread_Cache中去查找空闲的连接线程,如果存在则直接使用,不存在才创建新的连接线程。
有关Thread_Cache在MySQL有几个重要的参数:
1、thread_cache_size
Thread_Cache 中存放的最大连接线程数.在短连接的应用中Thread_Cache的功效非常明显,因为在应用中数据库的连接和创建是非常频繁的,如果不使用 Thread_Cache那么消耗的资源是非常可观的!在长连接中虽然带来的改善没有短连接的那么明显,但是好处是显而易见的.但并不是越大越好大了反而 浪费资源这个的确定一般认为和物理内存有一定关系,如下:
1G —> 8 2G —> 16 3G —> 32 >3G —> 64
如果短连接多的话可以适当加大。
2、thread_stack
每个连接被创建的时候,mysql分配给它的内存.这个值一般认为默认就可以应用于大部分场景了,除非必要非则不要动它.
3、thread_handing
运用Thread_Cache处理连接的方式,5.1.19添加的新特性.有两个值可选[no-threads|one-thread-per-connection]
no-threads 服务器使用一个线程
one-thread-per-connection 服务器为每个客户端请求使用一个线程.
通过以上3个命令,可以看到服务器的 thread_cache池中最多可以存放32个连接线程,为每个客户端球使用一个线程.为每个连接的线程分配192k的内存空间.
服务器总共有199156次连接,最大并发连接数为31,当前在thread_cashe池中的连接数为3个,连接数为6个,处于活跃状态的有5个,共创建 了8689次连接.显然这里以短连接为主.可以算出thread_cache命中率,公式为:
Thread_Cache_Hit=(Connections-Thread_created)/Connections*100%
当前服务器的Thread_cache命中率约为95.6%,但是可以看出 thread_cache_size有点多余。改成16或8更合理一些.
二、TABLE_CACHE(5.1.3及以后 版本又名TABLE_OPEN_CACHE)
由于MySQL是多线程的机制,为了提高性能,每个线程都是独自打开自己需要的表的文件描 述符,而不是通过共享已经打开的.针对不同存储引擎处理的方法当然也不一样.
在myisam表引擎中,数据文件的描述符 (descriptor)是不共享的,但是索引文件的描述符却是所有线程共享的.Innodb中和使用表空间类型有关,假如是共享表空间那么实际就一个数 据文件,当然占用的数据文件描述符就会比独立表空间少.
个人感觉有点像php里面的fopen打开一个连接,操作完数据之后,并不立即 关闭,而是缓存起来,等待下一个连接这个文件的请求就不必去重新打开文件了。
如果你正用 HANDLER tbl_name OPEN语句打开一个表,将为该线程专门分配一个表。该表不被其它线程共享,只有线程调用HANDLER tbl_name CLOSE或线程终止后才被关闭。表关闭后,被拉回表缓存中(如果缓存不满)。
mysql手册上给的建议大小 是:table_cache=max_connections*n
n表示查询语句中最大表数, 还需要为临时表和文件保留一些额外的文件描述符。
几个关于table_cache的 状态值:
1. table_cache:所有线程打开的表的数目。增大该值可以增加mysqld需要的文件描述符的数量。默认值是64.
2. open_tables:当前打开的表的数量.
3. opened_tables :Number of table cache misses,如果opened_tables较大,table_cache 值可能太小.
三、表的数量和临时表
1.mysql如何open和close表
mysql open表是通过句柄(file descriptor )来实现的,mysql是多线程的,在并发session open表的时候,mysql为每个session单独打开表的,通过内存cache住这部分信息,为后来open表所用,可以大大的提高open表的速度;对于打开一个myisam表,mysql要同时分配两个文件描述符,一个是数据文件描述符(线程之间不能共享),一个是索引文件描述符(线程之间可以共享),例如一个两个线程访问同一表或一个线程在一个查询中访问一个表两次,表都会被打开两次;而open其他的表只需要一个文件描述符。
mysql open一个表,并放入table cache中,那mysql什么时候close一个不用的表,并从tabl中e cache中删除呢?当满足如下条件时,开始准备删除table cache中的表
A. 当table cache已经满了,而又有一个线程需要open一个不在table cache中的表。
B. table cache里存在的条目比table_open_cache多,并且在table cache中的表不再被任何线程使用
C.当表有flush操作时,例如有人执行flush table语句、 mysqladmin flush-tables或mysqladmin refresh
2.一个database里应有多少表
在同个database里表数量不宜太多(300-500为宜),如果表太多,那么open、close和create operations都会很忙 ,这可能因为mysql的系统表都是myisam,不支持并发的原因.
3.mysql internal临时表的使用
当系统需要internal临时表的时候,首先在内存初始化为memory类型的表,随着数据的增长,mysql自动把内存中memory类型表转变为磁盘上myisam表,内存中的临时表是取变量 tmp_table_size和max_heap_table_size两个中最小的一个。
mysql server使用临时表的情况可以通过状态变量Created_tmp_tables 和 Created_tmp_disk_tables 来监控;只要创建临时表,变量Created_tmp_tables 就增加,创建磁盘临时表,变量值Created_tmp_disk_tables增加。通过这两个状态变量的监控可以方便设置变量tmp_table_size,来减少磁盘排序。
在什么条件下会出现使用磁盘临时表?
A. 表中出现blob和text列
B. 超过512bytes的group by或distinct
C. 当有union和union all被使用时,select list超过512bytes
如何确定一个查询是否使用临时表?
可以通过explain查看“Extra”列,看其是否有“Using temporary”
后面会分享更多关于DBA方面的内容,感兴趣的朋友可以关注下!!