2016-08-05 42 views
0

嗨我有一個產品類別數據庫,其中產品和類別使用第三個表格具有多對多關係,例如。產品分類。目前,進出口運行以獲取屬於類別ID陣列上給出一個類別中的所有產品數據庫的查詢,讓我們看看下面的例子:Mysql GROUP BY通過內部連接和大型數據集進行優化

SELECT * FROM products p JOIN product_category pc ON p.id = pc.product_id 
WHERE pc.category_id IN (1,2,3,4,5,6) GROUP BY p.id LIMIT 0,40 

產品表富人各地23K行和product_category表26k行。

通常,WHERE IN子句中使用的類別ID數組有更多的元素。

現在這個查詢需要300ms的來獲取結果。如果我刪除了GROUP BY子句,那麼查詢只需要2ms來獲取結果。

一個更完整的查詢如下:

select * from `products` inner join `product_category` on `products`.`id` = `product_category`.`product_id` 
     where `product_category`.`category_id` in ('1', '2', '3', '4', '5', '6', '7', 
    '8', '44', '155', '156', '157', '158', '159', '160', '161', '162', '168', '169', '171', '172', '173', '174', '175', '176', 
    '178', '179', '180', '181', '182', '183', '184', '185', '186', '189', '190', '191', '192', '193', '194', '195', '196', 
    '197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '213', '215', '216', '217', 
    '218', '219', '230', '231', '232', '233', 
    '234', '235', '236', '237', '240', '241', 
    '242', '243', '244', '245', '246', '247', 
    '248', '249', '250', '251', '252', '253', 
    '254', '255', '256', '257', '258', '259', 
    '260', '261', '325', '326', '327', '328', 
    '334', '335', '336', '337', '338', '339', '340', '341', '342', '343', '344') and `products`.`is_visible` = '1' 
    group by `product_category`.`product_id` 
    order by `popularity` desc, `popularity` desc limit 40 offset 0 

查詢的解釋如下:

Explain of the query

所以,我的問題是,如果有一種方法來優化通過特定的方式查詢組,以便不會花太長時間加載結果。

+0

既然你不是聚合,你有沒有嘗試過'SELECT DISTINCT p。*'呢? – Uueerdo

+0

@Uueerdo是的,我沒有改變,帶有選擇差異的查詢所花費的時間幾乎與羣組相同。謝謝 – asolenzal

+0

喲永遠不要按結構使用該組,因爲不能保證總是在沒有在組中指定的字段中給出相同的結果。僅僅因爲你可以做點什麼並不意味着你應該這樣做。按照其他數據庫要求的方式正確使用組。當你有一個連接時,也不要使用SELECT *,因爲它返回的數據比你需要的要多(連接字段重複),這會導致查詢速度慢。這兩個語法問題都是SQL反模式,如果你試圖通過真正理解數據庫的人來傳遞它,你會忽略代碼審查。 – HLGEM

回答

0

正如我在評論說,你可能有一些運氣SELECT DISTINCT p.*;但我通常看到使用GROUP BY人來解決DISTINCT緩慢......

另一種方法是使用子查詢,而不是直接的JOIN,就像這樣:

SELECT * 
FROM `products` 
WHERE id IN (
    SELECT DISTINCT `product_id` 
    FROM `product_category` 
    WHERE `category_id` IN ([category id list]) 
) 
AND `is_visible` = '1' 
ORDER BY `popularity` DESC, `popularity` DESC 
LIMIT 40 OFFSET 0 

SELECT p.* 
FROM `products` AS p 
INNER JOIN (
    SELECT DISTINCT `product_id` 
    FROM `product_category` 
    WHERE `category_id` IN ([category id list]) 
) AS pcSmry ON p.id = pcSmry.product_id 
WHERE p.`is_visible` = '1' 
ORDER BY `popularity` DESC, `popularity` DESC 
LIMIT 40 OFFSET 0 

編輯:如果沒有這些的幫助,你可能想看看在索引和WHERE條件ON使用的字段。