对mysql的优化不在行,搞过几次优化,但是都不是很理想,还是浪费资源太多。一直发现我的mysql的缓存命中率极差,情况良好的时候到达过60-70%,但是运行时间一长,只有10-20%。查了一些资料,关于缓存的一些参数记录
mysql> SHOW VARIABLES LIKE ‘%query_cache%’;
+——————————+———-+
| Variable_name | Value |
+——————————+———-+
| have_query_cache | YES |
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 67108864 |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
+——————————+———-+
6 rows in set (0.00 sec)
have_query_cache
是否支持查询缓存区 “YES”表是支持查询缓存区
query_cache_limit 可缓存的Select查询结果的最大值 1048576 byte /1024 = 1024kB 即最大可缓存的select查询结果必须小于1024KB
query_cache_min_res_unit 每次给query cache结果分配内存的大小 默认是 4096 byte 也即 4kB
经过我测试,
set GLOBAL query_cache_min_res_unit=4096; 的时候,碎片会比较多,在3000多。
set GLOBAL query_cache_min_res_unit=2046;的时候,碎片比较少,在1000多。
但是过小会增加IO负担
mysql>show status;
中间有一段 Qcache_开头的
Qcache_free_blocks | 4984 |
| Qcache_free_memory | 30097400 |
| Qcache_hits | 701669 |
| Qcache_inserts | 832414 |
| Qcache_lowmem_prunes | 41224 |
| Qcache_not_cached | 2654 |
| Qcache_queries_in_cache | 20527 |
| Qcache_total_blocks | 46362
1-(Qcache_hits /Qcache_inserts )是缓存命中率。
但是我总质疑干嘛要1减去这个数字,Qcache_hits 是命令的数量,那么Qcache_inserts是总数,命中数量除以总数,不就是命中率了,这里还要好好查查。
Qcache_free_memory 表示查询缓存区现在还有多少的可用内存
Qcache_hits 表示查询缓存区的命中个数,也就是直接从查询缓存区作出响应处理的查询个数
Qcache_inserts 表示查询缓存区此前总过缓存过多少条查询命令的结果
Qcache_lowmem_prunes 表示查询缓存区已满而从其中溢出和删除的查询结果的个数
Qcache_not_cached 表示没有进入查询缓存区的查询命令个数
Qcache_queries_in_cache 查询缓存区当前缓存着多少条查询命令的结果
这部分和我后来找到的另外的有些出入
MySQL查询缓存变量解释:
Qcache_free_blocks:缓存中相邻内存块的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理,从而得到一个空闲块。
Qcache_free_memory:缓存中的空闲内存。
Qcache_hits:每次查询在缓存中命中时就增大
Qcache_inserts:每次插入一个查询时就增大。命中次数除以插入次数就是不中比率。
Qcache_lowmem_prunes:缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间来看;如果这个 数字在不断增长,就表示可能碎片非常严重,或者内存很少。(上面的 free_blocks和free_memory可以告诉您属于哪种情况)
Qcache_not_cached:不适合进行缓存的查询的数量,通常是由于这些查询不是 SELECT 语句或者用了now()之类的函数。
Qcache_queries_in_cache:当前缓存的查询(和响应)的数量。
Qcache_total_blocks:缓存中块的数量。
query_cache_limit:超过此大小的查询将不缓存
query_cache_min_res_unit:缓存块的最小大小
query_cache_size:查询缓存大小
query_cache_type:缓存类型,决定缓存什么样的查询,示例中表示不缓存 select sql_no_cache 查询
query_cache_wlock_invalidate:当有其他客户端正在对MyISAM表进行写操作时,如果查询在query cache中,是否返回cache结果还是等写操作完成再读表获取结果。
query_cache_min_res_unit的配置是一柄”双刃剑”,默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费。
查询缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%
如果查询缓存碎片率超过20%,可以用FLUSH QUERY CACHE整理缓存碎片,或者试试减小query_cache_min_res_unit,如果你的查询都是小数据量的话。
查询缓存利用率 = (query_cache_size - Qcache_free_memory) / query_cache_size * 100%
查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。
查询缓存命中率 = (Qcache_hits - Qcache_inserts) / Qcache_hits * 100%
示例服务器 查询缓存碎片率 = 20.46%,查询缓存利用率 = 62.26%,查询缓存命中率 = 1.94%,命中率很差,可能写操作比较频繁吧,而且可能有些碎片。
引用一段前辈的话
优化提示:
如果Qcache_lowmem_prunes 值比较大,表示查询缓存区大小设置太小,需要增大 。
如果Qcache_free_blocks 较多,表示内存碎片较多,需要清理,flush query cache
根据我看的 《High Performance MySQL》中所述,关于query_cache_min_res_unit大小的调优
,书中给出了一个计算公式,可以供调优设置参考:
query_cache_min_res_unit = (query_cache_size - Qcache_free_memory) / Qcache_queries_in_cache
什么是MySQL查询高速缓冲?
查询缓存存储SELECT 查询的文本以及发送给客户端的相应结果。如果随后收到一个相同的查询,服务器从查询缓存中重新得到查询结果,而不再需要解析和执行查询。
缓存的效果如何?
- 如果执行的所有查询是简单的( 如从只有一行数据的表中选取一行) ,但查询是不同的,查询不能被缓存,查询缓存激活率是13% 。这可以看作是最坏的情形。在实际应用中,查询要复杂得多,因此,查询缓存使用率一般会很低。
- 从只有一行的表中查找一行数据时,使用查询缓存比不使用速度快2 38% 。这可以看作查询使用缓存时速度提高最小的情况
注意:
查询缓存不返回旧的数据。当表更改后,查询缓存值的相关条目被清空。
如果你有许多mysqld 服务器更新相同的MyISAM 表,在这种情况下查询缓存不起作用。
服务器启动时要禁用查询缓存,设置query_cache_size 系统变量为0 。禁用方式是通过在configure 中 使用--without-query-cache 选项,可以从服务器中彻底去除查询缓存能力。
查询高速缓冲工作原理是怎样的?
当查询解析之前先进行比较操作,SELECT * FROM table_name 和 Select * From table_name被认为是不同的两个操作,也就意味着查询操作必须是逐字节相同的操作语句串才能够使用高速缓冲;同样的查询字符串有可能认为是不同 的,如:使用不同的数据库、不同的协议版本或者不同的默认字符集的查询,所以高速缓冲将建立不同的查询缓冲。
当一个表被更改,那么使用那个表的所有缓冲查询将不再有效,并从缓冲区中移出。可能被哪些语句更改呢?它包括:INSERT UPDATE DELETE TRUNCATE ALTER TABLE DROP TABLE 和 DROP DATABASE。
SELECT SQL_CALC_FOUND_ROWS * ......和SELECT FOUND_ROWS() type类型的查询使用查询缓存。即使因创建的行数也被保存在缓冲区内,前面的查询从缓存中提取,FOUND_ROWS() 也返回正确的值。
哪些函数将不被缓存?
BENCHMARK() | CONNECTION_ID() | CURDATE() |
CURRENT_DATE() | CURRENT_TIME() | CURRENT_TIMESTAMP() |
CURTIME() | DATABASE() | 带一个参数的ENCRYPT() |
FOUND_ROWS() | GET_LOCK() | LAST_INSERT_ID() |
LOAD_FILE() | MASTER_POS_WAIT() | NOW() |
RAND() | RELEASE_LOCK() | SYSDATE() |
不带参数的UNIX_TIMESTAMP() | USER() |
引用自定义函数、变量、Mysql系统数据库中的表。
SELECT ... IN SHARE MODE
SELECT ... FOR UPDATE
SELECT ... INTO OUTFILE...
SELECT ... INTO DUMPFILE ...
SELECT * FROM ... WHERE autoincrement_col IS NULL
使用TEMPORARY 表
不使用任何表
用户有某个表的列集权限。
如何设置查询高速缓冲SELECT 选项?
SQL_CACHE:如果query_cache_type系统变量的值是ON或DEMAND,查询结果被缓存。
SQL_NO_CACHE:查询结果不被缓存。
如何设置查询高速缓冲配置?
通过have_query_cache服务器系统变量指示查询缓存是否可用。
SHOW VARIABLES LIKE 'have_query_cache';
所有查询缓存系统变量名以query_cache_ 开头。为了设置查询缓存大小,设置query_cache_size 系统变量。设置为0 表示禁用查询缓存。 默认缓存大小设置为0 ;也就是禁用查询缓存。当设置query_cache_size 变量为非零值时,应记住查询缓存至少大约需要40KB 来分配其数据结构。( 具体大小取决于系统结构)。 如果你把该值设置的太小,将会得到一个警告。
SET GLOBAL query_cache_size = 40000;
SHOW WARNINGS/G
如果查询缓存大小设置为大于0 ,query_cache_type 变量影响其工作方式。这个变量可以设置为下面的值:
- 0 或OFF 将阻止缓存或查询缓存结果。
- 1 或ON 将允许缓存,以SELECT SQL_NO_CACHE 开始的查询语句除外。
- 2 或DEMAND ,仅对以SELECT SQL_CACHE 开始的那些查询语句启用缓存。
当一个查询结果(返回给客户端的数据)从查询缓冲中提取期间,它在查询缓存中排序。因此,数据通常不在大的数据块中处理。查询缓存根据数据排序要求分配数据块,因此,当一个数据块用完后分配一个新的数据块。因为内存分配操作是昂贵的( 费时的) ,所以通过query_cache_min_res_unit 系统变量给查询缓存分配最小值。当查询执行时,最新的结果数据块根据实际数据大小来确定,因此可以释放不使用的内存。根据你的服务器执行查询的类型,你会发现调整query_cache_min_res_unit 变量的值是有用的:
设置query_cache_type 变量的GLOBAL 值将决定更改后所有连接客户端的缓存行为。具体客户端可以通过设置query_cache_type 变量的会话值控制它们本身连接的缓存行为。例如,一个客户可以禁用自己的查询缓存,方法如下:
mysql> SET SESSION query_cache_type = OFF;
要控制可以被缓存的具体查询结果的最大值,应设置query_cache_limit 变量。 默认值是1MB 。
当一个查询结果(返回给客户端的数据)从查询缓冲中提取期间,它在查询缓存中排序。因此,数据通常不在大的数据块中处理。查询缓存根据数据排序要求分配数据块,因此,当一个数据块用完后分配一个新的数据块。因为内存分配操作是昂贵的( 费时的) ,所以通过query_cache_min_res_unit 系统变量给查询缓存分配最小值。当查询执行时,最新的结果数据块根据实际数据大小来确定,因此可以释放不使用的内存。根据你的服务器执行查询的类型,你会发现调整query_cache_min_res_unit 变量的值是有用的:
- query_cache_min_res_unit 默认值是4KB 。这应该适合大部分情况。
- 如果你有大量返回小结果数据的查询,默认数据块大小可能会导致内存碎片,显示为大量空闲内存块。由于缺少内存,内存碎片会强制查询缓存从缓存内存中修整(删除)查询。这时,你应该减少query_cache_min_res_unit 变量的值。空闲块和由于修整而移出的查询的数量通过Qcache_free_blocks和Qcache_lowmem_prunes 变量的值给出。
· 如果大量查询返回大结果(检查 Qcache_total_blocks 和Qcache_queries_in_cache 状态变量),你可以通过增加query_cache_min_res_unit 变量的值来提高性能。但是,注意不要使它变得太大(参见前面的条目)。