优化实例:1 查找与用户同一地区性别为女的信息,按照最后登录时间排序
前提是:数据库有百万数据,而且用户访问很频繁
查询SQL:select * from user where area = '$area' and sex = '$sex' order by lastlogin desc limit 0 ,30;
需要注意的是,数据库中有百万条数据,但这里只要求检索出30条数据就可以
如果单纯的只在area上建立索引,首先会检索出所有area匹配的数据(因为建了索引,所以这是很快的),但是其他的字段没有建立索引,所以还要在命中sex,仍然会检索地区是$area的数据量。如果建立了area和sex的复合索引,效果略好,但仍然会检索area = '$area' and sex = '$sex',然后排序。如果建立了area sex 和lastlogin的复合索引,该索引基于area sex和lastlogin的三个字段合并排序,很轻松的就能将数据检索处理,而且只需要检索出30条数据,无需检索百万数据。
认识影响结果集,影响结果集是检索数据所检索的行数,输出结果集是真正返回的行数,对我们起真正决定意义的还是影响结果集。
影响结果集的范例:
查询语句:select users from user where area = '北京' and sex = '女'
假设索引为area,假设所有的用户共有1000000人,北京的用户有100000人,那影响结果集就是100000人。而不是1000000,这样的话对于性能有一定的好处,但10w也不是个小数目,北京的女性用户有50000人,这样因为索引是area所以,影响结果集是100000,而返回结果集是50000.如果没有索引的话,影响结果集就是1000000,输出结果集是50000,这是多么可怕的事情啊,要检索1000000条数据,这在数据库中基本上市不可能存在的事情我觉得,因为但凡有这么多是数据量,一定会有专门的DBA来维护,DBA是不允许这种事情发生的。如果对area 和sex做复合索引呢?那影响结果集就是50000,输出结果集还是50000.效率很高,虽然检索了50000条数据,但这是用户确切需要的,其他优化还在继续,而索引能做的,就这么多了。在扩展一下,如果在sql后面加一个limit 0,30;很明显输出结果集就是30条数据,而当我们对area和sex进行索引的时候,以为索引已经是排序过的,索引只需要检索出30条数据来就可以了,非常方便。但是如果我么在Limit前面加上order by lastlogin的话呢?很明显之前没有对Lastlogin建索引,所以影响结果集是50000而输出结果集还是30,这是非常浪费资源的,所以解决办法就是对area sex 和lastlogin建立复合索引。
优化实例:2 毫秒级优化案例
游戏用户登录后台,显示最新账户信息。
查询为: select * from user where uid = $uid order by timeline desc limit 20;
这是高频操作,每天有数百万次次执行,出现的问题:因为该搜索每执行一次的影响结果集是几百至几千条数据,在上千条结果集的情况下,该sql查询开销通常在0.01秒左右,建立uid+timeline复合索引,将排序引入到索引结构中,影响结果集就变成了20,每条sql查询的开销变成了0.001,数据库负载骤降。
优化实例:3 Innodb锁表案例
某游戏数据库的存储引擎是innodb,innodb是行表锁,理论上来说很少存在锁表情况。有一条语句,
delete grom username where uid = $uid
该语句执行的很少,每天大约只执行10次,20次左右,但这个数据库表容量百万级,而且悲催的是这个uid未建立索引,于是更悲催的事发生了,由于未建立索引,每次执行该操作的时候,delete遍历全表,全表被delete锁定,由于百万条记录遍历时间过长,期间大量select被阻塞,导致数据库连接崩溃。
优化实例:4 论坛翻页优化
select * from post where tagid = '$tagid' order by lastpost limit $start,$end;
如果是超级热帖,几万个回帖,用户频繁翻页,limit 25700,100,那将是很可怕的事。
我的思路:首先肯定是要建索引,tagid和lastpost的复合索引,但翻到末页的时候也会有很大的影响结果集,很明显单纯的使用索引优化是不够 ,我们可以从两方面来优化。一:改变sql语句,目的是减少影响结果集,这种方法也是我借鉴的别人的,自己完全没有思路。获得当前页的最大值$maxlast和最小值$minlast,然后将sql语句修改为:select * from post where lastpost >$minlast and lastpost < $maxlast;这样
影响结果集就变成了$end,效率获得了极大的提升。而且这种情况不适合建立静态页面或者见缓存,因为是实时更新的。
Mysql执行状态监控
show processlist
执行状态分析:
sleep 连接过多导致,资源未释放,表示数据库一直运行,数据库未断开。
locked 更新操作锁定,更新表示可能是插入 修改 和删除,通常使用INNODB可以很好的减少表锁,在myisam中locked是很多高并发 应 用的噩梦,所以官方也开始推荐使用INNODB;
其他的不做介绍了,太多了,不会经常见到的
sendingdata sql语句优化的不够好,通常是影响结果集太大