2017-02-25 66 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的哪一行对应于删除的子句。