2011-09-11 79 views
2

解決見下文索引與GROUP BY,ORDER BY,和GROUP_CONCAT

我試圖同時使用GROUP BYORDER BY我的查詢中,我通過檢索難度排序的數據。我必須使用GROUP BY,因爲GROUP CONCAT因爲某些表(如'lookup_peripheral')將多個值鏈接到同一個鍵(content_id)。我明白爲什麼MYSQL在執行此任務時不能使用索引,因爲GROUP BY和ORDER BY語句不共享相同的字段。但是,我正在尋找不需要一天就可以檢索結果的替代解決方案。

如果我省略GROUP BYORDER BY子句,那麼數據庫將使用索引,但結果缺少所有外圍設備,或者沒有按難度排序。

我正在使用FROM中的'lookup_difficulty'表,因此我可以使用該索引來排序結果。 lookup_xxxxx表存儲每個允許的值,然後其他表(例如peripheral)通過content_id將提交鏈接到值。一切都參考了提交content_idcontent表持有必要的信息,如會員ID,名稱等。

如果我的帖子不夠清晰,我表示歉意。

mysql> describe peripheral; 
+------------------+----------+------+-----+---------+-------+ 
| Field   | Type  | Null | Key | Default | Extra | 
+------------------+----------+------+-----+---------+-------+ 
| peripheral_id | int(2) | NO | PRI | NULL |  | 
| peripheral  | char(30) | NO |  | NULL |  | 
| peripheral_total | int(5) | NO |  | NULL |  | 
+------------------+----------+------+-----+---------+-------+ 

mysql> select * from peripheral; 
+---------------+-----------------+------------------+ 
| peripheral_id | peripheral  | peripheral_total | 
+---------------+-----------------+------------------+ 
|    1 | periph 1  |    0 | 
|    2 | periph 2  |    1 | 
|    3 | periph 3  |    3 | 
+---------------+-----------------+------------------+ 

mysql> describe lookup_peripheral; 
+---------------+---------+------+------+---------+-------+ 
| Field   | Type | Null | Key | Default | Extra | 
+---------------+---------+------+------+---------+-------+ 
| content_id | int(10) | NO | INDEX| NULL |  | 
| peripheral_id | int(2) | NO |  | NULL |  | 
+---------------+---------+------+------+---------+-------+ 


mysql> mysql> select * from lookup_peripheral; 
+------------+---------------+ 
| content_id | peripheral_id | 
+------------+---------------+ 
|   74 |    2 | 
|   74 |    5 | 
|   75 |    2 | 
|   75 |    5 | 
|   76 |    3 | 
|   76 |    4 | 
+------------+---------------+ 

上lookup_difficulty不使用索引下面,而是一個表格排序和臨時表。

SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral, content.member, ..... 
FROM (lookup_difficulty) 
LEFT OUTER JOIN lookup_peripheral ON lookup_difficulty.content_id = lookup_peripheral.content_id 
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id 
..... 
LEFT OUTER JOIN programmer ON programmer.programmer_id = lookup_programmer.programmer_id 
LEFT OUTER JOIN lookup_programming_language ON lookup_difficulty.content_id = lookup_programming_language.content_id 

GROUP BY lookup_difficulty.content_id 
ORDER BY lookup_dfficulty.difficulty_id 
LIMIT 30  

的最終目標是獲取與連接了正確的外設難度排序結果。我想我需要一個子查詢來實現這一點。


編輯:回答以下:

想通了。我做了我所懷疑的我必須做的事情,那就是添加一個子查詢。由於MYSQL每張表只能使用一個索引,因此我無法將GROUP BYSORT BY一起用於我的特定設置。相反,我添加了另一個查詢,它將使用另一個表上的另一個索引將外設組合在一起。在這裏我添加在SELECT上述聲明:

(SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral 
FROM lookup_peripheral 
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id 
WHERE lookup_difficulty.content_id = lookup_peripheral.content_id 
GROUP BY lookup_peripheral.content_id 
LIMIT 1) as peripheral 

我用LEFT OUTER因爲某些條目沒有任何外設。對於大多數表格,400MHz處理器上的總查詢時間現在爲.02s,對於40k行數據庫,具有128MB的100Hz RAM。

EXPLAIN現在爲lookup_difficulty表提供了一個USING INDEX。我加入這個以實現:

ALTER TABLE `pictuts`.`lookup_difficulty` DROP PRIMARY KEY , 
ADD PRIMARY KEY (`difficulty_id` , `content_id`) 

編輯2 我注意到,通過使用分頁大偏移,該頁面將加載慢得多。您也可能在其他網站上體驗過這一點。幸運的是,有一種方法可以避免這一點,正如Peter Zaitsev所指出的那樣。這是我更新的代碼段來實現相同的時序爲30K或0偏移:

FROM 
SELECT lookup_difficulty.content_id, lookup_difficulty.difficulty_id 
FROM lookup_difficulty 
LIMIT '.$offset.', '.$per_page.' 
) ld 

現在只需加ld.whateverJOIN製成,有你有它!我的查詢看起來像是一團糟,但至少它已經過優化。我想沒有人會做這麼遠在讀這...

+2

請考慮在下面發佈您的解決方案作爲答案。這樣你可以將問題標記爲已回答。 – Wolph

+0

我不能等到8個小時了...... – Justin

+0

@Justin,現在8小時了。 – Johan

回答

2

投入Justin的答案,所以這個問題下車沒有答案的列表:

想通了。我做了我懷疑我必須做的事情,那就是添加一個子查詢。由於MYSQL每個表只能使用一個索引,因此我無法將GROUP BY和SORT BY一起用於我的特定設置。相反,我添加了另一個查詢,它將使用另一個表上的另一個索引將外設組合在一起。下面是我在上面的SELECT語句中加入:

(SELECT group_concat(DISTINCT p.peripheral) as peripheral 
FROM lookup_peripheral lp 
LEFT JOIN peripheral p ON p.peripheral_id = lp.peripheral_id 
WHERE ld.content_id = lp.content_id 
GROUP BY lp.content_id 
LIMIT 1) as peripheral 

我使用LEFT OUTER因爲有些項目沒有任何外設。對於大多數表格,400MHz處理器上的總查詢時間現在爲.02s,對於40k行數據庫,具有128MB的100Hz RAM。

現在解釋給了我一個用於lookup_difficulty表的USING INDEX。我加入這個以實現:

ALTER TABLE pictuts.lookup_difficulty DROP PRIMARY KEY , 
ADD PRIMARY KEY (difficulty_id , content_id) 

編輯2我注意到,通過使用分頁大偏移,該頁面將加載慢得多。您也可能在其他網站上體驗過這一點。幸運的是,Peter Zaitsev指出,有一種方法可以避免這種情況。這是我更新的代碼段來實現相同的時序爲30K或0偏移:

FROM 
SELECT ld.content_id, ld.difficulty_id 
FROM lookup_difficulty ld 
LIMIT '.$per_page.' OFFSET '.$offset.' 
) ld 

現在只需加ld.whatever到每個連接製成,有你有它!我的查詢看起來像是一團糟,但至少它已經過優化。我不認爲任何人在閱讀這篇文章時都會做到這一點......