2013-10-31 59 views
3

我有一個MySQL的Percona的5.6.13數據庫表是這樣的:如何優化我的數據庫查詢而不反量化?

CREATE TABLE `table1` (
    `table1_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `created_at` datetime NOT NULL, 
    PRIMARY KEY (`table1_id`), 
    KEY `created_at` (`created_at`) 
) ENGINE=InnoDB; 

CREATE TABLE `table2` (
    `table1_id` int(10) unsigned NOT NULL, 
    `cost` decimal(6,2) NOT NULL DEFAULT '0.00', 
    KEY `table1_id` (`table1_id`) 
) ENGINE=InnoDB; 


CREATE TABLE `table3` (
    `table1_id` int(10) unsigned NOT NULL, 
    `partner` enum('partner1', 'partner2', 'partner3', 'partner4') NOT NULL DEFAULT 'partner1', 
    KEY `table1_id` (`table1_id`) 
) ENGINE=InnoDB; 

每個表格都在他們大約150萬行。

當我運行以下查詢時,每次需要18秒。

SELECT t3.partner, SUM(t2.cost) AS cost FROM table1 t1 JOIN table2 t2 ON t1.table1_id = t2.table1_id JOIN table3 t3 ON t1.table1_id = t3.table1_id WHERE t1.created_at >= '2005-07-01' AND t1.created_at < '2008-09-20' GROUP BY 1; 

如果我非規範化的成本/合作伙伴字段表1,像這樣:

ALTER TABLE table1 ADD `cost` decimal(6,2) NOT NULL DEFAULT '0.00', ADD `partner` enum('partner1', 'partner2', 'partner3', 'partner4') NOT NULL DEFAULT 'partner1', ADD KEY `partner` (`partner`); 
UPDATE table1 t1 JOIN table2 t2 ON t1.table1_id = t2.table1_id SET t1.cost = t2.cost; 
UPDATE table1 t1 JOIN table3 t3 ON t1.table1_id = t3.table1_id SET t1.partner = t3.partner; 

,然後再運行此查詢:

SELECT t1.partner,SUM(t1.cost )AS cost FROM table1 t1 WHERE t1.created_at> ='2005-07-01'AND t1.created_at <'2008-09-20'GROUP BY 1;

第一次需要6秒,然後每次2秒(因爲大概是mysql緩存)。

我猜想我希望找到的可能是某種優化/緩存原始查詢的方式,而不會使數據非規格化。
我不能只合並這些表格(因爲這個例子中沒有包括的其他字段,但是我爲了測試目的而刪除了這些字段)。我可以在表格中複製數據,但我並不是那麼喜歡,而且似乎應該有比這更好的解決方案。
要嘗試的任何數據庫設置?
也許NoSQL具有更完全的非規格化數據 - 在這種場景下,聚合工作是否合理快速?
謝謝:)

p.s.一個評論要求查詢計劃 - where子句選擇的行數是全部。同樣的結果,如果我離開關在那裏,這裏是查詢計劃:

+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+ 
| id | select_type | table | type | possible_keys  | key  | key_len | ref     | rows | Extra              | 
+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | t1 | range | PRIMARY,created_at | created_at | 5  | NULL     | 766380 | Using where; Using index; Using temporary; Using filesort | 
| 1 | SIMPLE  | t3 | ref | table1_id,partner | table1_id | 4  | lsfs_main.t1.table1_id |  1 | NULL              | 
| 1 | SIMPLE  | t2 | ref | table1_id   | table1_id | 4  | lsfs_main.t1.table1_id |  1 | NULL              | 
+----+-------------+-------+-------+--------------------+------------+---------+------------------------+--------+-----------------------------------------------------------+ 
+0

索引您在連接中使用的列? – sevenseacat

+0

如果你看看創建表查詢,我相信我已經有了需要創建的所有索引。在連接中使用的唯一字段是table1_id,並且它在所有3個表中都被索引。 –

+0

什麼是查詢執行計劃?結果中典型的行數是多少? –

回答

1

你丟失的主鍵table2table3。我建議至少包含所有兩列的多列主鍵table3。由於InnoDB-Tables是索引組織表,因此這應該會顯着減少table3的查找。有了這樣的主鍵,MySQL可以直接從索引中檢索所有相關數據,而無需進一步查找。字段table1_id必須位於多列主鍵的第一個位置。

對於table2這並不容易,因爲(table1_id, cost)不是唯一的。

+0

我實際上可以爲我的示例至少添加table2和table3的多列主鍵。我喜歡這個想法,所以我會盡快答覆你的答案,儘管它實際上並沒有解決我的問題。我嘗試添加您建議的密鑰,但沒有任何區別。我認爲加入是昂貴的,這是問題。也許我會以不同的方式重述這個問題。我希望得到一些關於mysql服務器參數的建議來嘗試調整,或者可能有關於nosql的信息,所以我會更具體地說明這一點。謝謝 :) –