1.优化概要
使系统变快的最重要因素是系统的基础设计.我们需要知道系统正在做什么类型的处理,以及瓶颈是什么.多数情况下,系统瓶颈主要来源于以下几个方面:
1.1 磁盘访问(Disk seek). 即找到一片数据所花的时间,现代磁盘的平均时间通常小于10ms,相当于每秒寻址100次.由于硬件的限制及很难对单一的表进行优化,所以优化磁盘访问时间的最好办法就是将数据分布在多个磁盘上.
1.2 磁盘读写(Disk reading and writing). 现代磁盘的吞吐量大约在10-20MB/s,可以通过从多个磁盘并行读取来提升速度.
1.3 CPU周期(CPU cycles). 经比较,小表的内存量是最常见的限制因素,但对小表来说,速度通常不是问题.
1.4 内存带宽(Memory bandwidth). 当CPU自身的缓存不能满足需求时,主存带宽便成了一个瓶颈,但对大多数系统来说,这并不是一个常规的瓶颈问题,然而我们需要知道它的存在.
2. SELECT及其它查询语句优化
2.1 使用EXPLAIN优化查询,参考EXPLAIN手册
2.2 评估查询性能
多数情况下,我们可以通过计算磁盘搜索次数来估算查询性能. 对比较小的表来说,通常可以通过一次磁盘搜索就可以找到相应的行(row).对比较大的表来说,在使用BTREE索引的情况下,可以通过下面的公式来估算找到一行的搜索次数:
log(
row_count
) / log(index_block_length
/ 3 × 2 / (index_length
+ data_pointer_length
)) + 1
在MYSQL中,index_block_length通常为1024个字节,data_pointer_length通常为4个字节,因此对于一个具有50万条记录的表来说,如果键值长度为4个字节(INT),则通过上式可得:
log(500000)/log(1024/3x2/(4+4))+1=5.28 (约等于6次)
如果磁盘的搜索访问时间为10ms,那么在50万条记录中查找一条时间大约是52.8ms
2.3 加速SELECT查询
通常,使SELECT...WHERE变快的第一件事情,就是要检查是否添加了索引(index).不同表之间的所有引用,原则上都是通过索引来完成的.
3.数据库结构优化
3.1 使数据表尽可能的小
一个最基本的优化方式就是使表尽可以占用小的存储空间,为了得到更好的性能及减少存储空间,可以采用下面的技术:
3.2 单列索引(Column Indexes)
MySQL的所有数据类型都可以成为索引,在相关的列上加索引是为了更好的提高SELECT操作的性能.每个表的最多索引数及每个索引的最大长度,都会因存储引擎的不同而有所不同.但所有存储引擎都支持至少16个索引/表,及至少256字节/索引. 需要特别指出的是,列索引前缀的是按字节进行计算的,而在CREATE TABLE中的INDEX(blob_col(10))中的10会被解析成字符.(在使用多字节字符集时要务必考虑). 当然我们要也可以创建FULLTEXT索引用于全文索引,在MYSQL中仅MyISAM引擎支持且仅对CHAR,VARCHAR,及TEXT类型有效. MEMORY存储引擎默认采用HASH索引,但也支持BTREE(B树)索引.
3.3 多列索引(Multiple-Column Indexes)
在MySQL中还可以合建组合索引,即一个索引指向多个列.一个索引最多可以由16个列组成. 可以将一个多列索引,想像成一个被排序的数组,数组的内容就是相关列内容的粘合. 多列索引只有当第一个列的值在WHERE语句中以确定值出现时才起作用,即使没有指派其它列值也无妨.
如: CREATE TABLE test(....,....,INDEX NAME(col1,col2)); 当执行SELECT语句时,只有在
WHERE col1=c(一个确定的值)[AND,OR col2=var] 的情况下起作用,且在where col1=c1 or col2=c2的条件下也不会起作用.
3.4 MySQL如何使用索引
MySQL会在以下操作中使用索引:
B-Tree索引可以使用比较运算符:=,>,>=,<,<=和BETWEEN,除些之外还可以应用于LIKE,但 LIKE的参数不能以通匹符%开始.
3.5 MyISAM 键值缓存(Key Cache),参考设置: key_buffer_size or key_cache_block_size
3.6 InnoDB缓冲池
InnoDB通过在主存中维护一个缓冲池来缓存数据和索引,并将其作为一个列表来处理,使用LRU算法并纳入了中点插入策略. 当需要加入一个新块时,INNODB会使用LRU算法替换出相应的块,并将新块插入到列表的中间.中点插入策略会有效地将列表分成两个子列表:在头部(head),是最近被使用的"新"块的子列,位于尾部的(tail),是最近很少用的"旧"块.
InnoDB有些系统变量,可以用来控制缓冲池的大小或改善LRU算法
3.7 MySQL是如何开关表的
MySQL是多线程的,所以在同一时刻可能会有多个客户端在查询同一个表,因此为了减少在同一个表上,因多个会话具有不同状态而导致的问题,每一个并行的会话都会独立地打开表.这样做会使用额外的内存,但也会提高性能. 对于MyISAM表来说,每个客户端都会需要一个额外的数据文件(data file)的描述文件;相反,所有会话会共享一个索引描述文件. table_open_cache,max_connections,以及max_tmp_tables,都会影响系统同时打开文件的数量.
3.8在同一数据库下创建太多表的坏处
如果在同一数据库下有太多的MyISAM表,那么打开,关闭和创建操作会变得很慢.当在很多不同的表上执行SELECT时,会在table cache满时,会有小的开销,因为要打开新的表,就必须得关掉其它的表,为些,可以通过适应提高table_open_cache值,为降低这种开销.
4.MySQL Server优化
4.1系统因素与启动参数优化
操作系统的选择是非常重要的.为了使多CPU机器发挥出最佳性能,应该Solaris或Linux操作系统.除此之外,还可以参与以下帮助信息:
4.2 启动参数优化
我们可能通过以下命令来查看MYSQL当前系统变量值及SERVER状态:
MYSQL的算法设计应该是很灵活的,所以只需要很少的内存就可以运行.但是,如果给予更多内存的,就会得到更好的恨不能.
MYSQL SERVER优化中两个最重要的变量是:key_buffer_size与table_open_cache, 因此在尝试修改其它变量之前,需要确定这两个变量已经被正确或切当的设置.
4.3 控制查询优化器性能
查询优化器的任务是找到一个对执行某个SQL查询最优的方案.因为优化性能在"好"与"坏"之间的差异可以是以数量级算的,所以很多的查询优化器,包括MYSQL的,会在所有可能的查询评估方案中,或多或少地详尽搜索出一个最优方案. 就连接查询(join)而言,MYSQL优化器的优化方案会随查询中涉及表的数目成指数增长. 对少于7-10表的查询来说,这不是问题,但是,如果更多的查询被提交,那么在查询优化上所花的时间就会成为服务器性能的主要瓶颈.
通常的观点是,优化器可供选择的方案越少,其在编译查询时所花的时间就越少;另一方面,因为优化器忽略了一些方案,所以有可能就失去了最佳方案. 优化器的可用评估方案的数量,可通过下面两个系统变量来控制:
4.4 MySQL查询缓存(query cache)
SELECT语句及其返回结果都会放入到查询缓存中,如果再有同样的语句出现,服务器会从查询缓存中读取结果.查询缓存是SESSION共享的,因此一个客户端产生的结果,同样也可以被另外一个客户端采用. 查询缓存不会返回过时的数据,当对应表被更新时,缓存中的相应条目都会被刷新.
查询缓存可以提供大量的性能改进的潜力,但是您不能认为在所有情况下都如此.在不同的查询缓存配置或服务器工作负载,可能会出现性能下降的情况:
4.4.1 查询缓存如何运作
服务器在收到查询语句并解析之前,先查看查询缓存中有没有一样的语句.需要注意的是相比较的两个查询语句必须绝对的一致才可以,即大小也是敏感的. 且缓存不会用在以下情况:
当从查询缓存中返回结果之后,服务器会将Qcache_hits值 加1.
如果某个表发生了改变,那么缓存中所有与此表相关的查询都将被从缓存中移除.
4.4.2 查询缓存SELECT参数
4.4.3 查询缓存配置
系统通过判断have_query_cache来判断是否需要缓存,通过query_cache_size来设定缓存大小,如果为0,则说明查询缓存功能关闭,如果不为0,那么query_cache_size的最小值是40KB,小于时会提示警告(show warnings\G). 如果query_cache_size大于0,那么query_cache_type将影响其工作方式:
可以通过query_cache_limit 来限定每个查询可缓存的记录大小,默认为1M. 查询缓存在需要时通过申请内存块来存储数据,因此当一个块已经满时,另一个新块又会被申请.因为内存申请操作的代价是比较昂贵的,所有我们需要用query_cache_min_res_unit来指定每个块的最小大小.当一个查询被执行之后,最近申请的结果块会被修剪成实际的大小,而没有使用到的部分会被释放掉. 依据不同的查询类型,通过调整query_cache_min_res_unit可以达到比较好的效果:
4.4.4 查询缓存状态与维护
通过FLUSH QUERY CACHE 可以进行碎片整理,且不会多缓存中移除任何查询,如果执行REST QUERY CACHE 或 FLUSH TABLES则会从查询缓存中移除所有查询结果.