2012-07-16 76 views
1

我的MySQL數據庫有超過3.5億行,並且正在增長。它現在有32GB的大小。我使用固態硬盤和大量內存,但想尋求建議,以確保我使用適當的索引。爲查詢優化MySQL索引(交易時間戳數據庫)

CREATE TABLE `qcollector` (
    `key` bigint(20) NOT NULL AUTO_INCREMENT, 
    `instrument` char(4) DEFAULT NULL, 
    `datetime` datetime DEFAULT NULL, 
    `last` double DEFAULT NULL, 
    `lastsize` int(10) DEFAULT NULL, 
    `totvol` int(10) DEFAULT NULL, 
    `bid` double DEFAULT NULL, 
    `ask` double DEFAULT NULL, 
    PRIMARY KEY (`key`), 
    KEY `datetime_index` (`datetime`) 
) ENGINE=InnoDB; 

show index from qcollector; 
+------------+------------+----------------+--------------+-------------+-----------+-- -----------+----------+--------+------+------------+---------+---------------+ 
| Table  | Non_unique | Key_name  | Seq_in_index | Column_name | Collation |  Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| qcollector |   0 | PRIMARY  |   1 | key   | A   | 378866659 |  NULL | NULL |  | BTREE  |   |    | 
| qcollector |   1 | datetime_index |   1 | datetime | A   | 63144443 |  NULL | NULL | YES | BTREE  |   |    | 
+------------+------------+----------------+--------------+-------------+-----------+------ -------+----------+--------+------+------------+---------+---------------+ 
2 rows in set (0.03 sec) 

select * from qcollector order by datetime desc limit 1; 
+-----------+------------+---------------------+---------+----------+---------+---------+--------+ 
| key  | instrument | datetime   | last | lastsize | totvol | bid  | ask | 
+-----------+------------+---------------------+---------+----------+---------+---------+--------+ 
| 389054487 | ES   | 2012-06-29 15:14:59 | 1358.25 |  2 | 2484771 | 1358.25 | 1358.5 | 
+-----------+------------+---------------------+---------+----------+---------+---------+--------+ 
1 row in set (0.09 sec) 

是緩慢的一個典型的查詢(全表掃描,這個查詢需要3-4分鐘):

explain select date(datetime), count(lastsize) from qcollector where instrument = 'ES' and datetime > '2011-01-01' and time(datetime) between '15:16:00' and '15:29:00' group by date(datetime) order by date(datetime) desc; 
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows  | Extra          | 
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+ 
| 1 | SIMPLE  | qcollector | ALL | datetime_index | NULL | NULL | NULL | 378866659 | Using where; Using temporary; Using filesort | 
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+ 

回答

1

一對夫婦的想法,你要考慮:

  • 覆蓋索引(即,包括所有在查詢中引用的列的索引)可以幫助一些。這樣的索引將需要更多的磁盤(SSD?)空間,但它將消除MySQL訪問數據頁以查找不在索引中的列的值的必要性。

    ON qcollector (datetime,instrument,lastsize)

    ON qcollector (instrument,datetime,lastsize)

  • 你真的需要排除有lastsize從計數NULL值的行?你可以返回所有行的計數嗎?如果您可以返回COUNT(1)SUM(1),則查詢不需要引用lastsize列,因此索引中不需要使其成爲覆蓋索引。

    COUNT(lastsize)表達相當於SUM(IF(lastsize IS NULL,0,1))

  • 你需要的時候有隻爲日期時間範圍NULL值lastsize,或者可以全部用一個空行的lastsize排除返回的日期?也就是說,你可以包括像

    AND lastsize IS NOT NULL

在查詢謂詞?

這些可能會有所幫助。


我認爲最大的問題是,在TIME(datetime)表達的謂詞不是可優化搜索。也就是說,MySQL不會爲這些使用索引範圍掃描操作。在裸露的datetime列上的謂詞是可靠的...這就是爲什麼EXPLAIN將datetime_index顯示爲可能的關鍵。

而另一個大問題是查詢對派生表達式執行GROUP BYORDER BY操作,該派生表達式將要求MySQL生成中間結果集(作爲臨時MyISAM表),然後處理該結果集。當有很多行要處理時,這可能會造成很大負擔。


至於表的變化,我會考慮使用單獨的DATE和TIME列,並在地方DATETIME的使用TIMESTAMP數據類型(如果你需要存儲的日期和時間一起)。我會重寫查詢來引用裸DATE和裸TIME列,並考慮添加一個覆蓋索引,其中包含重寫查詢中引用的所有列,其中前導列是具有最高基數的列(並且具有最多選擇性謂詞查詢。)

+0

如果我添加覆蓋索引(比如datetime,lastsize)[或新建議的結構],但查詢不使用其中一列,索引是否仍會被使用?或者在這種情況下我需要兩個單獨的索引嗎? – ctrlbrk 2012-07-17 00:07:05

+0

關於使用COUNT,我經常使用SUM來代替 - 通常在特定時間範圍內 – ctrlbrk 2012-07-17 00:09:58

+0

@ user1530260:您希望單個索引包含所有列。單獨列上的索引不會幫助您查詢。 (它們可能對其他查詢有用。)但是對於您的查詢,您需要一個索引。 – spencer7593 2012-07-17 03:20:54

1

當您在列中使用datetime功能指標不能有效地使用。您還可以將日期和時間存儲在單獨的列中並對其進行索引,但這會佔用更多的存儲空間。

您可能還需要考慮添加多列索引。 (instrument, datetime)上的索引可能會幫助你。

+0

大多數查詢使用'yyyy-mm-dd hh:mm:ss'和'yyyy-mm-dd hh:mm:ss'(跨度只有一兩天)之間的日期時間,所以我發現它很多更好地使用日期時間的單個列而不是兩個單獨的列。但是,有些查詢(如上所述)需要數月或數年,而且我需要在每天的某個時間(hh:mm:ss)中包含這些時間。 – ctrlbrk 2012-07-16 23:27:32

+0

還有不到10個'樂器',我的理解是在這種情況下索引不會有幫助。 – ctrlbrk 2012-07-16 23:29:24

+0

如果您希望查詢時間跨度很長,但每天僅選擇幾次,則需要對時間進行索引。在MySQL中,不幸的是唯一的方法是創建一個新列,因爲它[不支持功能索引](http://bugs.mysql.com/bug.php?id=4990)。 – 2012-07-16 23:33:48