第一篇 序章
第二篇 连接优化
第三篇 索引优化
第四片 查询优化
第五篇 到实战中去
查询优化
查询优化涉及到用户查询数据时使用到的索引、排序、group 等操作,以及其书写习惯。(原文链接http://ddbiz.com/?p=990)
-
影响查询的服务器参数调整
除了用户的查询习惯外,在整个数据查询的处理期间,mysql服务器中有些参数同样影响这些查询的执行,比如临时表、临时文件等。
-
max_heap_table_size
命令行参数: –max_heap_table_size=#
ini/cnf定义: max_heap_table_size
mysql 变量: max_heap_table_size
全局变量,可动态调整, 默认值为16M, 可调整范围32bitOS 16k到4G,64bitOS 16k到你能提供的可用内存量(最大1Zetta)用于存储引擎为 MEMORY 的用户表
-
tmp_table_size
命令行参数: –tmp_table_size=#
ini/cnf定义: tmp_table_size
mysql 变量: tmp_table_size
全局变量,可动态调整, 默认值以系统设定,最大值4Gtmp_table_size是mysql在执行group时,生成的内存表的大小限制,和max_heap_table_size一样,这是一个字节大小值。在系统中此值将和要查询的表的行长进行计算,用以决定mysql可以装载的表的行数。如果查询中的一个限制超过此值,在3.x以后的版本中,mysql会自动把这个临时表改换为磁盘文件:MyISAM 引擎。用户主动创建的内存表是不包含在此限制中的。
根据状态 :created_tmp_disk_tables 和 created_tmp_tables 来判定是否需要增加 tmp_table_size。
受如下参数影响: max_head_table_size
将影响如下参数:
调整触发条件: 当created_tmp_disk_tables超过created_tmp_tables时,应该采取行动提高tmp_table_size值.特别说明:在下列情况下,内存临时表将不能发挥作用,mysql将直接使用 MyISAM
- 表中有TEXT或者BLOB字段的情况
- group by 或者 distinct 指定的字段中,存在有长度大于512字节的字段的情况
- 在union/union all的select中,select 的字段有大于512字节的情况
在下列情况,mysql有可能把内存临时表转换为MyISAM引擎
- 查询中order by 与 group by 的字段不同
- 在join查询中,order by或者 group by包含了不是第一个表的字段
- 对distinct查询使用order by 排序
注意:max_heap_table_size和tmp_table_size在分配给一个连接线程查询时,其取值是 min(max_heap_table_size,tmp_table_size), 如果一个站点的并发连接(show status like ‘thread_running’)很多,则系统内存会分配=min(max_heap_table_size,tmp_table_size) * (show status like ‘thread_running’)。比如并发1000的站点中,如果每个连接可分配的内存是16m,那么临时内存将被分配 16m * 1000=16g. 如果你有那么多内存可供使用,那么这不是问题,否则的话,还是要把 tmp_table_size设置小一些。
当然,这也提示我们,在一个实时站点中,因为每个用户请求都不可能也不应该执行一个相对来讲很复杂或涉及很多记录的查询,对于一些统计工作,应该把统计用的数据库和online trancation数据库分开。 -
max_tmp_tables
根据文档(mysql5.5CE),此参数尚未启用!
-
query_prealloc_size
命令行参数: –query_prealloc_size=#
ini/cnf定义: query_prealloc_size
mysql 变量: query_prealloc_size
全局变量,可动态调整, 默认值8k,最大值4G(32bitOS)或更高(64bitOS).
query_prealloc_size 用于MySQL对SQL语句进行分析和执行的内存空间设定。当执行大的复杂的查询时,可以考虑针对SESSION增加此值。 -
query_cache_* 查询结果缓存
查询缓存是指两类:查询的SELECT语句以及查询的结果。这是一些列的系统变量设定:
query_cache_size: select查询的结果缓存,0或者40k到4G(32bitOS)或更高(64bitOS),默认为0;
query_cache_type: OFF:不缓存查询结果;ON:缓存除了SELECT SQL_NO_CACHE开头的所有查询结果;DEMAND:只缓存SELECT SQL_CACHE开头的查询结果。
query_cache_limit: 可以缓存的最大值字节数。
query_cache_min_res_unit:查询缓存分配的最小块大小,默认4k.
query_cache_wlock_invalidate:MySQL5.5中默认为OFF,只是是否在WRITE lock存在时组织其他客户查询。注意事项:
–>对于特别频繁的小查询来说(比如返回结果小于或者远小于query_cache_min_res_unit),很容易造成大量的内存碎片。
–>对于结果集较大的查询来说,足够大的query_cache_min_res_unit可以提高系统的性能。
通过对系统状态 Qcache_free_blocks 和 Qcache_lowmem_prunes 的查询来确定是否需要调整query_cache_min_res_unit。Qcache_free_blocks 查询缓存中空闲的内存块
Qcache_lowmem_prunes 表明了因为查询缓存不足而有查询结果被从缓存中移除的数量。
-
-
深入理解Query Cache
Query_cache_size在MySQL中默认是0,也就是说查询缓存默认是关闭的。既然查询缓存可以很好的提高用户的查询体验,为什么会被关闭呢?这要从MySQL的客户端编程来讲。Query_Cache_Size中的查询缓存,是依照查询语句作为键值来缓存结果的。查询语句必须要完全相同:大小写、空格、乃至查询变量。等等,为什么查询变量也会影响这个键值呢?原因很奇特:MySQL的客户端查询语句,使用的是直接变量替换,而不是像Oracle中那样的变量代入。看下面的这个查询例子:
public function GetUserByAccount($dbname, $host, $username, $userpwd, $charset, $account)
{
$sql = "select id from tmp_userhere";
if (CTextHelper::IsValidEmail($account))
$sql .= ‘ where email=:key‘;
else
$sql .= ‘ where username=:key‘;
$sql .= ‘ limit 3‘;
$dsn = "mysql:dbname=".$dbname.";host=".$host;
$dbh = new PDO($dsn, $username, $userpwd);
$charset = isset($charset) ? $charset :"gbk";
$this->dbh->exec("set names ".$charset);
$sth = $dbh->prepare($sql);
$sth->bindParam(‘:key‘, $account);
$r = $sth->execute();
if (!$r) return false;
return $sth->fetchColumn(0);
}
尽管在客户端(php代码)中使用的是变量绑定, 而实际的服务器跟踪看到的却是:
对于一个超大的数据表的查询来说,完全相同的查询几率太小了。所以完全可以省下这个Query Cache的设置。在我的某个大数据量的查询中,就让他是0吧。 -
用户的查询习惯
有很多人为的因素都会影响到查询的效率。我不打算在这里一一列举,可以在 Top 10 SQL Performance Tips中看到各种各样的优化语句的技巧。
-
Group By
如果查询语句中使用到Group By,一般来说,MySQL将建立一个临时表,然后对数据进行计算和排序,这时是不使用索引的。如下面的查询:
如果数据量很大,那么这个查询肯定会很慢。但是MySQL有一种方式,可以运行group by 通过索引来计算,条件是,group by中的所有字段都是一个索引中的列。
WORKING ON…,and KEEP EYES ON IT…