我有一个使用InnoDB的表,它存储了我系统发送的所有消息。目前该表有4000万行,每月增长3/4百万。
我的查询基本上是选择从用户发送的消息和数据范围内的消息。这是一个简单的创建表:
CREATE TABLE `log` ( `id` int(10) NOT NULL DEFAULT '0', `type` varchar(10) NOT NULL DEFAULT '', `timeLogged` int(11) NOT NULL DEFAULT '0', `orig` varchar(128) NOT NULL DEFAULT '', `rcpt` varchar(128) NOT NULL DEFAULT '', `user` int(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `timeLogged` (`timeLogged`), KEY `user` (`user`), KEY `user_timeLogged` (`user`,`timeLogged`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
注意:由于其他查询,我也有单独的索引。
查询如下所示:
SELECT COUNT(*) FROM log WHERE timeLogged BETWEEN 1282878000 AND 1382878000 AND user = 20
问题是此查询需要2分钟到10分钟,具体取决于用户和服务器负载,这是等待页面加载的时间太长。我在应用程序中启用了mysql缓存并缓存,但问题是当用户搜索新范围时,它不会命中缓存。
我的问题是:
AFAIK,我的索引已正确创建,此查询不会花这么长时间。
感谢所有帮助过的人!
答案 0 :(得分:1)
你正在使用innodb但没有充分利用你的innodb聚集索引(主键),因为它看起来像你的典型查询形式:
select <fields> from <table> where user_id = x and <datefield> between y and z
不
select <fields> from <table> where id = x
以下文章可以帮助您优化查询的表格设计。
http://www.xaprb.com/blog/2006/07/04/how-to-exploit-mysql-index-optimizations/
如果你理解正确的文章,你应该找到类似以下的东西:
drop table if exists user_log;
create table user_log
(
user_id int unsigned not null,
created_date datetime not null,
log_type_id tinyint unsigned not null default 0, -- 1 byte vs varchar(10)
...
...
primary key (user_id, created_date, log_type_id)
)
engine=innodb;
以上是来自上述设计的一些查询性能统计数据:
<强>计数强>
select count(*) as counter from user_log
counter
=======
37770394
select count(*) as counter from user_log where
created_date between '2010-09-01 00:00:00' and '2010-11-30 00:00:00'
counter
=======
35547897
基于用户和日期的查询(所有查询都使用冷缓存运行)
select count(*) as counter from user_log where user_id = 4755
counter
=======
7624
runtime = 0.215 secs
select count(*) as counter from user_log where
user_id = 4755 and created_date between '2010-09-01 00:00:00' and '2010-11-30 00:00:00'
counter
=======
7404
runtime = 0.015 secs
select
user_id,
created_date,
count(*) as counter
from
user_log
where
user_id = 4755 and created_date between '2010-09-01 00:00:00' and '2010-11-30 00:00:00'
group by
user_id, created_date
order by
counter desc
limit 10;
runtime = 0.031 secs
希望这会有所帮助:)
答案 1 :(得分:0)
COUNT(*)
未从表缓存加载,因为您有一个WHERE子句,使用EXPLAIN作为@jason提到,尝试将其更改为COUNT(id)并查看是否有帮助。
我可能错了,但我也认为您的索引必须与WHERE子句的顺序相同。由于您的WHERE子句在timeLogged
之前使用user
,因此您的索引应为KEY
user_timeLogged (
timeLogged ,
user)`
同样,EXPLAIN会告诉你这个索引的变化是否有所作为。