2017-02-25 68 views
0

將Prestashop實例從MySQL遷移到MariaDB後,過濾後的搜索查詢變慢。這是一個這樣慢的查詢的例子。從MySQL遷移到MariaDB後,Prestashop搜索速度變慢

SELECT 
    fl.name feature_name, 
    fp.id_feature, 
    fv.id_feature_value, 
    fvl.value, 
    COUNT(DISTINCT p.id_product) nbr, 
    lifl.url_name name_url_name, 
    lifl.meta_title name_meta_title, 
    lifvl.url_name value_url_name, 
    lifvl.meta_title value_meta_title, 
    psi.price_min, 
    psi.price_max, 
    m.name 
FROM 
    ps_feature_product fp 
INNER JOIN 
    ps_product p 
ON 
    (p.id_product = fp.id_product) 
LEFT JOIN 
    ps_feature_lang fl 
ON 
    (
     fl.id_feature = fp.id_feature AND fl.id_lang = 2 
    ) 
INNER JOIN 
    ps_feature_value fv 
ON 
    (
     fv.id_feature_value = fp.id_feature_value AND(
      fv.custom IS NULL OR fv.custom = 0 
     ) 
    ) 
LEFT JOIN 
    ps_feature_value_lang fvl 
ON 
    (
     fvl.id_feature_value = fp.id_feature_value AND fvl.id_lang = 2 
    ) 
LEFT JOIN 
    ps_layered_indexable_feature_lang_value lifl 
ON 
    (
     lifl.id_feature = fp.id_feature AND lifl.id_lang = 2 
    ) 
LEFT JOIN 
    ps_layered_indexable_feature_value_lang_value lifvl 
ON 
    (
     lifvl.id_feature_value = fp.id_feature_value AND lifvl.id_lang = 2 
    ) 
INNER JOIN 
    ps_product_shop product_shop 
ON 
    (
     product_shop.id_product = p.id_product AND product_shop.id_shop = 1 
    ) 
INNER JOIN 
    `ps_layered_price_index` psi 
ON 
    (
     psi.id_product = p.id_product AND psi.id_currency = 2 AND psi.id_shop = 1 
    ) 
LEFT JOIN 
    `ps_manufacturer` m 
ON 
    (
     m.id_manufacturer = p.id_manufacturer 
    ) 
WHERE 
    product_shop.`active` = 1 AND product_shop.`visibility` IN("both", "catalog") AND fp.id_feature = 9 AND p.id_product IN(
    SELECT 
     id_product 
    FROM 
     ps_category_product cp 
    INNER JOIN 
     ps_category c 
    ON 
     (
      c.id_category = cp.id_category AND c.id_category = 13 AND c.active = 1 
     ) 
) AND p.id_product IN(
SELECT 
    id_product 
FROM 
    ps_feature_product fp 
WHERE 
    fp.`id_feature_value` = 39 
) AND p.id_product IN(
SELECT 
    id_product 
FROM 
    ps_feature_product fp 
WHERE 
    fp.`id_feature_value` = 18 
) AND p.id_product IN(
SELECT 
    id_product 
FROM 
    ps_feature_product fp 
WHERE 
    fp.`id_feature_value` = 13 
) AND p.id_product IN(
SELECT 
    id_product 
FROM 
    ps_feature_product fp 
WHERE 
    fp.`id_feature_value` = 44 
) AND p.id_product IN(
SELECT 
    id_product 
FROM 
    ps_feature_product fp 
WHERE 
    fp.`id_feature_value` = 3186 
) 
GROUP BY 
    fv.id_feature_value 
ORDER BY 
    fv.position 

有趣的是,它得到了很多更快(4S VS 0.4秒),如果多一個(幾乎相同)的子查詢的WHERE子句中被刪除。

... AND 
/* 
-- removing any of the six product filters makes 
-- the query a lot faster 
p.id_product IN(
    SELECT 
     id_product 
    FROM 
     ps_feature_product fp 
    WHERE 
     fp.`id_feature_value` = 18 
) 
*/ 
AND ... 

下面是這個查詢的EXPLAIN輸出(沒有修改)。

是否有什麼東西明顯,需要以某種方式改變了嗎?所有表格都已經優化,沒有任何改進。

+0

爲什麼你最後有5個相同的子查詢?難道你不能只用'where fp.id_feature_value = 39或fp.id_feature_value = 18'來創建一個子查詢,依此類推? – TheDrot

+0

進行查詢的軟件是Prestashop – Andris

回答

2

你有這幾條:

AND p.id_product IN (
     SELECT id_product 
      FROM ps_feature_product fp 
      WHERE fp.`id_feature_value` = 39) 

它可以變成這個

AND EXISTS (SELECT * FROM ps_feature_product 
        WHERE id_product = p.id_product 
        AND id_feature_value = 39) 

IN (SELECT ...)優化很差。

一定要有INDEX(id_product, id_feature_value)

MySQL和MariaDB之間性能差異的原因在於,幾個優化改進在5.6左右發生了分歧。他們涉及與你在做什麼有關的東西。

比如像

 LEFT JOIN ps_layered_indexable_feature_value_lang_value lifvl 
       ON (lifvl.id_feature_value = fp.id_feature_value 
       AND lifvl.id_lang = 2 

需要複合INDEX(id_feature_value, id_lang)(以任一次序)。但我可以從EXPLAIN猜測你有這樣的情況。

請爲每個表提供SHOW CREATE TABLE,可能會有更多的建議。

我無法解決您的具體問題,因爲我不知道EXPLAIN的哪一行對應於刪除的子句。