2010-12-01 105 views
2

我有一個使用InnoDB的表,它存儲了我的系統發送的所有消息。目前這張桌子有四千萬行,每月增長三百四十萬。與大表的Mysql:如何優化此查詢?

我的查詢基本上是選擇從用戶發送並在數據範圍內的消息。這裏是一個簡單的創建表格:

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緩存並緩存,但問題是,當用戶搜索新的範圍時,它不會命中緩存。

我的問題是:

  • 會改變user_timeLogged指數有什麼區別?
  • 這是MySQL和大型數據庫的問題嗎?我的意思是,Oracle或其他數據庫是否也遭受這個問題?

AFAIK,我的索引已正確創建,並且此查詢不應該花這麼長時間。

感謝任何幫助的人!

+2

後從以下`EXPLAIN SELECT COUNT(*)FROM日誌WHERE timeLogged之間的輸出1282878000 AND 1382878000 AND user = 20;` – 2010-12-01 21:29:57

+0

我會將它作爲註釋發佈,但它並未解決查詢優化問題,但是您是否考慮過歸檔策略而不是將所有消息保留在單個表中?以750k /月的速度記錄4000萬條記錄意味着超過四年的數據。除非確實是在任意時代的消息以相同的頻率查詢,否則您可能需要考慮將舊消息移動到單獨的表中,並實施將舊消息的請求引導到該表的邏輯。 – 2010-12-01 21:43:05

回答

0

COUNT(*)不從表緩存加載,因爲你有一個WHERE子句,使用EXPLAIN作爲@jason提到,嘗試將其更改爲COUNT(id)並查看是否有幫助。

我可能是錯的,但我也認爲你的索引必須與WHERE子句的順序相同。由於您的WHERE子句user之前使用timeLogged那麼你的指數應KEY user_timeLogged ( timeLogged ,用戶)`

同樣,EXPLAIN會告訴你,這個指標變化是否有差別。

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/

如果你正確地理解文章,你應該找到youself的東西,如下列:

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 

希望這有助於:)