* 我们经常会碰到以下的场景
mysql中的用户数据(以下例子中以邮件为例)达到上百万级别,单个用户的邮件上万,
当进行用户邮件记录查询时需要支持按照时间,按照标题,和按照收件人进行排序,
排序之后还要分页显示(用户邮件可能会分上千页),当用户选择3000 页,5000页,
或者是尾页的时候,性能很差
* 构造测试数据模型
表结构
create table user_mail
(
id int(9) NOT NULL auto_increment,
user_id int(9) NOT NULL,
subject varchar(128),
creating_time datetime,
from_addr varchar(128),
detail varchar(1024),
PRIMARY KEY(id)
);
数据库为MyISAM, 字符集Latin-1
生成测试数据的程序,代码如下, 产生300万条数据, 对应1000个用户,数据300万条(每个人3000条左右浮动)
#include
为了测试较差的情况,特别让其中一个用户关联大量记录, 执行下面的语句
update user_mail set user_id=900 where user_id>900;
数据统计,编号0 ~ 899的用户的邮件数目在3000左右浮动,900号用户的数据为30万( 下面的测试均针对900号用户进行查询 ),数据一共300万
使用本机 mysql (5.0.21), 本机配置 , IBM think pad T61, 双核 1.8G, 2G 内存
创建索引
create index i_user_mail_subject on user_mail(user_id,subject);
下面是执行的查询
select * from user_mail where user_id=900 order by subject limit 100 offset ???
offset 执行时间
100 0.01秒
1000 0.03秒
10000 0.25秒
100000 1.63秒
最差情况的这个用户,当我选择尾页邮件的时候,数据库的负载极高,而且耗时超过2秒
创建索引
create index i_user_mail_subject1 on user_mail(user_id,subject,id);
下面是执行的查询
select * from user_mail um
inner join (
select id from user_mail where user_id=900 order by subject limit 100 offset ???
) page on page.id=um.id;
offset 执行时间
100 0.01秒
1000 0.02秒
10000 0.03秒
100000 0.24秒
优化做法的sql语句和普通做法的sql是等价的,但是速度相差8倍左右
可以看到当查询offset 10000时,只用了30ms,性能杠杠的
covering index
查询的所有字段在索引里都可以找到,这样查询的时候只用找索引就可以了
这就是为什么优化算法中建立索引是三列主键
select id from user_mail where user_id=900 order by subject limit 100 offset 10000
上面的sql会很快,因为id, user_id, subject都能应用索引
如果写成
select * from user_mail where user_id=900 order by subject limit 100 offset 10000
就会慢很多
所以优化算法中先查询出小结果集(100条)的id, 然后再进行join查询,查询其他字段的值