myisam,可以基于blob和text的前500字节,创建索引
myisam 支持fulltext
延迟更新索引
(delay_key_write)
CREATE TABLE `table3` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) DEFAULT NULL,
`id2` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8 DELAY_KEY_WRITE = 1
ALTER TABLE table2 DELAY_KEY_WRITE = 1
只有myisam支持全文检索
字段尽可能的小
尽量避免null,用0代替。但是对性能的提升很小,最后考虑,索引的列最好不适用null
一、优化数据访问
查询性能低下的最基本原因就是访问了太多数据。一些查询不可避免的要筛选大量的数据,单这并不常见。大部分性能欠佳的查询都可以用减
少数据访问的方式进行修改。在分析性能欠佳的查询的时候,下面两个步骤比较有用:
1.应用程序是否在获取超过需要的数据。这通常是访问了过多的行或列。
2.mysql服务器是否分析了超过需要的行。
对于访问的数据行很大,而生成的结果中数据行很少,可以尝试修改。
1.使用覆盖索引,它存储了数据,所以存储引擎不会去完整的行。
2.更改架构,一个例子就是使用汇总表。
3.重写复杂的查询,让mysql的优化器可以优化的执行。
二、复杂查询和多个查询
1.把一个复杂的查询分解为多个简单的查询。(mysql一般的服务器,每秒钟可以处理50 000个查询)
2.
三、缩短查询
将一次处理大量数据的操作,分解为多个小操作。循环的方式每次处理一部分数据。一次删除不要超过10 000行(delete)
四、分解链接
把一个多表连接分解成多个单个查询,然后在应用程序里实现联接。
这样的优势
1.缓存效率高。
2.mysql,可以更有效的利用表锁,查询会锁住单个表较短时间。
3.应用程序进行联接可以更方便的拓展数据库,把不同表放在不同服务器上。
4.查询更高效。
5.可以减少多余的行访问,可以减少网络流量和内存消耗。
小结:在程序端进行联接的效率更高
1.可以缓存早期查询的大量数据。
2.使用了多个myisam表
3.数据分布在不同的服务器上。
4.对于大表使用in替换联接
5.一个连接引用了同一个表多次。
当你重建汇总和缓存表的时候,在操作的时候你常常需要它们的数据保持可见。你可以使用“shadow table”(影像表)来实现。当你已经创建它之后,你可以使用原子性的重命名来交换这些表。举个例子,如果
你需要重建my_summary,你能创建my_summary_new,填充数据,把它和真正的表作交换。
mysql> DROP TABLE IF EXISTS my_summary_new, my_summary_old;
mysql> CREATE TABLE my_summary_new LIKE my_summary;
-- populate my_summary_new as desired
mysql> RENAME TABLE my_summary TO my_summary_old, my_summary_new TO my_summary;
mysql执行查询的一般性过程
1.客户端发送查询到服务器
2.服务器检查查询缓存,
3.服务器解析,预处理和优化查询,生成执行计划。
4.执行引擎调用存储引擎api执行查询。
5.服务器将结果发送到客户端。
mysql客户端、服务器协议
1.协议是半双工的。mysql服务器在某个时间可以发送或者接受数据,单不能同时发送和接收。所有没有办法阶段消息。
2.客户端用一个数据包将查询发送到服务器,所以max_packet_size这个配置参数对于大查询很重要的原因。
3.客户端从服务器提取数据的时候是服务器产生数据的同时把它们“推”到客户端的,客户端只需要接收推出来的数据,无法告诉服务器停止
发送数据。
查询缓存
SELECT SQL_NO_CACHE * FROM ol_answerlog LIMIT 1000
SHOW STATUS LIKE 'last_query_cost'
关键字straight_join 强制执行引擎按照查询中表现的顺序来进行链接操作。
严格的说,mysql不回尝试减少读取的行数,它只会试着优化对页面的读取,但是行数可以大致显示查询的开销。
连接优化器试着产生最低开销的查询计划。在可能的时候,他会从单表计划开始,检查所有的可能的子树的组合。但是对n个表连接,需要检
查组合的数量就是n的阶乘,这个数量称为ie搜索空间, 它增长非常快,如果一个查询需要连接10个表,那么要检查的数量将是10!=36288000
当搜索空间非常巨大的时候优化耗费的时间就会非常长,这时候服务器就不回执行完整的分析,但表的数量超过optimizer_search_depth的值
时,它就会走捷径,比如执行所谓的 贪婪搜索。
SHOW TABLE STATUS FROM `servant_591up`WHERE ENGINE IS NOT NULL
AND NAME LIKE '%ol_ans%';
max min的优化
select min(id) from ol_user where username = 'dddd@dd.com'
(一)max 和 min 会扫描整张表。
mysql的主键都是按照升序排列的。
可以使用limit 改写查询,
select userid from ol_user where username='test@nd.com' limit 1
(二)对同一表进行select 和 update
mysql不允许对一个表进行update的时候进行select
update tb1 as out_table
set cnt = (select count(*) from tb1 as inner_table where inner_table.type = outer_table.type);
一个实现方式:衍生表,当成临时表来处理。
update tb1 inner join(
select type,count(*) as cnt
from tb1
group by type
)as der using(type)
set tb1.cnt = der.cnt;
(三、)优化特定类型的查询
1.count
count的作用 统计值的数量和统计行的数量
值是非空表达式(NOT NULL)
一个常见的错误就是在想统计行数的时候,在count的括号中放入列名,如果想知道结果的行数,应该总是使用COUNT(*),这可以清晰的说明意
图,并且得到好的性能。
2.MYISAM
只有在没有WHERE条件的时候COUNT(*)才是最快的,在有条件过滤的时候并不非常快。
3.简单优化
可以利用MYISAM对COUNT(*)的优化对已经有索引的一小部分做统计。
SELECT COUNT(*) FROM WORD.CITY WHERE ID>5;
优化为下面的语句
SELECT (SELECT COUNT(*) FROM CITY) - COUNT(*) FROM CITY WHEREID<=5;
这样的explain只扫描6行数据
使用一个查询统计同一列中不同值的数量。
select sum(if(color='blue',1,0)) as blue,sum(if(color='red',1,0)) as red from items;
下面是一个等价查询
select count(color='blue' or null) as blue,count(color='red' or null) as red from items;
(四)优化联接
1.确保on 或using使用的列上有索引。
通常只需要在联接中的第2个表上添加索引就可以。
2.确保group by或order by只引用一个表中的列。这样可以使用索引。
3.谨慎升级mysql
(五)优化子查询
对于子查询,尽可能的使用联接。
(五)优化group by和distinct
1.主要方式:索引
2.优化group by的策略:临时表或文件排序分组。
SQL_SMALL_RESULT : 强制使用临时表
SQL_BIG_RESULT :强制使用文件排序
通常对表的id进行分组会更加高效
可以使用SQL_MODE参数禁止SELECT中使用在group by中出现的列
子查询创建的临时表不支持索引。
所以要让子查询创建的临时表尽可能的小。
3.使用ROLL UP 优化GROUP BY
WITH ROLLUP
最好的方式是将WITH ROLLUP 放在应用程序里。
注意: Rollup 与 order by 相互排拆
(六)优化limit和offset
LIMIT 和ORDER BY 一块使用。
如果没有索引,就使用文件排序。
(七)优化SQL_CALC_FOUND_ROWS
这个地方很重要
一个技巧:在含有limit的查询中添加SQL_CALC_FOUND_ROWS,这样就可以知道没有limit的时候会返回多少行数据。服务器会预测将会发现多少
行数据。但是服务器并不能真正的做到,只是告诉服务器生成结果并丢掉结果中不需要的部分。而不是在得到需要的数据后就立即停止。这个
选项代价很高。
一个非常好的设计:
如果每页有20条结果,那么应该查询limit 21行数据,只显示20条,如果结果中有21行,那么就会有下一页。
另一种方式:就是提取并缓存大量数据,比如1000行,然后从缓存中获取后续页面的数据。
可以让程序知道一共有多少数据,少于1000,程序知道有多少页,如果大于1000,可以显示找到的结果超过1000个。
这两种都比重复产生完整的结果效率高。
如果以上两种都不可以使用,可以使用覆盖索引,使用单独的count(*)会更好
(八)优化联合 union
mysql总是使用临时表来执行union,无法做更多的优化
重要的是,一定要使用union all,除非真的是需要服务器消除重复的行,
否则mysql会使用distinct选项,来确保所有行数据的唯一性。
(九)查询优化提示
可以用一些提示控制优化器的行为,每个提示只影响当前查询。
1.HIGH_PRIORITY 和 LOW_PRIORITY
HIGH_PRIORITY 让mysql 将一个select语句放在其他的语句的前面,mysql将它放在队列的前面,而不是在队列中等待。可以用在insert语句中
。
low——priority正好相反,可以用在SELECT INSERT UPDATE REPLACE DELETE
这两个选项在表锁的存储过程中有效,在innerdb无效,在myisam要小心使用,严重影响性能,禁止并发插入。
2.delayed
用户insert delete
立即返回,放入缓冲当中,,无法使用LAST_ISNERT_ID()
3.STRAIGHT_JOIN
强制mysql按照查询中表出现的顺序来连接表。
出现在两个连接的表中间时,强制这两个表按照顺序连接。
用途:mysql没有选择更好的链接,或者优化器需要花费很长时间来确定连接顺序。
4.SQL_SMALL_RESULT SQL_BIGA_RESULT
用在group by 和distinct语句中的,如何使用临时表
SQL_SMALL_RESULT :结果很小,可以放在索引过的临时表中,
SQL_BIGA_RESULT:结果很大,最好使用磁盘上的临时表进行排序。
5.SQL_BUFFER_RESULT
将结果放在临时表中,并且要尽快释放掉表锁。
6.SQL_CACHE SQL_NO_CACHE
7.SQL_CALC_FOUND_ROWS
在limit自居计算完整的结果集,可以通过found_ROWS()来取得它的行数,
最好不使用这个提示、
8.FOR_ UPDATE 和 LOCK IN SHARE MODE
只有innodb支持,提示控制锁定,仅对行锁起作用。select语句中
9.USE INDEX 和 IGNORE INDEX 和 FORCE INDEX
控制索引的使用,在mysql5.1中,还有 FOR ORDER BY FOR GROUP BY
用途:告诉优化器表扫描比索引代价高很多,
重要的系统变量
Optimizer_search_depth
优化器检查执行计划的深度。
Optimizer_prune_level
根据检查的行数来决定跳过一些查询计划。
(九) 用户自定义变量
一些需要注意的问题:
会禁止缓存
不能用于文字常量和标识的地方(表名,列名,limit)
和连接有关,不能跨通信使用
如果使用连接池,会引起代码隔离
mysql 5.0大小写敏感
不能显示的声明类型,最好的方式给变量显示的一个初始值 0 0.0 ‘’,
用户自定义变量的类型是动态的,赋值的时候才会变化。
优化器有时候会把变量优化掉。
set @ont:=1; :=运算符的优先级,低于其他的,最好使用括号()。。 也可以使用=赋值,最好统一使用:=
未定义的变量不会引起语法错误,很容易犯错。
五、mysql高级特性
查询缓存命中率
Qcache_hits/(Qcache_his+Com_select) show status
1.缓存未命中原因
查询不可缓存,不确定函数。CURRENT_DATE,结果太大, Qcache_not_cached 会记录两种无法缓存的查询数量。
服务器以前从来没见过这个缓存。
查询结果被缓存过,但是服务器把它移除。
很多缓存失效。
2.很多缓存未命中,但是不能缓存的查询很少。
查询缓存未被激活。
服务器看到了以前未见过的查询
缓存失效。
A:如何对查询缓存进行维护调优
Query_cache_type
表示缓存是否被激活,on off demand,demand:只有sql_cache的查询才可以被缓存。
Query_cache_size
缓存的总内存,字节单位。1024的倍数,
Query_cache_min_res_unit
分配缓存块的最小值
Query_cache_limit
限制了mysql存储的最大结果。如果超过这个值,会丢掉已经缓存过的值,并增加Query_not_chched的值。如果是这样需要在查询上增
加QUERY_NO_CACHE
Query_cache_wlock_invalidate
是否缓存其他链接已经锁定了的表,默认off,
B:优化的一些法则
减少碎片
需要仔细选择Query_cache_min_res_unit,可以避免在查询缓存中造成大量的内存浪费。
最佳设置根据典型查询结果确定。可以使用内存(Queryc_cache_size - Query_free_memory)除以Query_queries_in_cache
得到查 询的平均大小。可以通过query_cache_limit的值来阻止缓存大结果。
可以检查Qcache_free_blocks来探测缓存中碎片的情况,显示缓存中有多少内存块出于free状态。如果Qcache_free_blocks
大致 等于Qcache_total_blocks/2,则说明碎片非常严重,如果Qcache_lowmen_prunes的值在增加并且有大量的
自由块,说明碎片导致查 询整 被从缓存中永久删除。
可以使用FLUSH QUERY CACHE命令移除碎片。会把所有的存储块向上移动,把自由块移动到底部。会阻止访问查询缓存,锁定
整个服务器,通常这个速度很快,不会移除缓存中的数据,
RESET QUERY CACHE会清除缓存数据。
提高缓存可用性。
如果没有碎片,但是命中率不高,应该给缓存分配较少的内存。
服务器清理查询的时候会Qcache_lowmen_prunes的值会增加,如果值增加的过快则说明:
1.如果自由块很多,碎片
2.如果自由块比较少,说明工作负载使用的内存超过所分配的内存。可以检查Qcache_free_memory知道未使用的内
存。
可以禁用缓存查看缓存是否真的有效果
query_cacha_size = 0,可以关闭缓存(query_cache_type 无法影响已经打开了的链接,也不会把内存归还给服务
器。)
5.1.5 innodb和查询缓存
6.2.2 myisam键缓存
SHOW VARIABLES LIKE 'key_buffer_size'
键缓冲区,myisam本身只缓存索引,没有数据。
应该让key_buffer_size占到保留内存的25-50%。但是对于mysql5.0,最大上限都是4G
但是可以创建多个命名键缓冲区。可以一次在内存中保存4G以上的数据。
key_buffer_1 key_buffer_2 都是1G
在配置文件增加两行
key_buffer_1.key_buffer_size = 1G
key_buffer_2.key_buffer_size = 1G
可以使用cache index 命令把表映射到缓存
也可以用下面的命令把表的索引保存到key_buffer_1
cache index t1,t2 in key_buffer_1
也可以使用load index把表的索引预加载到缓存中
load index into cache t1,t2;
缓存命中率
100-((Key_reads * 100) / Key_read_requests)
缓存使用百分比
100-((Key_blocks_unused * key_cache_block_size) * 100 / key_buffers_size)
innodb 可以使用裸设备
raw