简体   繁体   English

如何优化通过NOT IN或NOT EXISTS过滤的MySQL查询内部的性能

[英]How to optimize performance inside MySQL Query filtered via NOT IN or NOT EXISTS

One query what I have perform low performances by adding one query filter. 通过添加一个查询过滤器,我查询的一项性能低下。

Here is full query: 这是完整的查询:

SELECT
    `c`.`categories_id`,
    `c`.`section_id`,
    `c`.`categories_status`,
    IF(`c`.`categories_status` = 1, 'ON', 'OFF') AS `categories_status_name`,
    TRIM(`cd`.`categories_name`) AS `categories_name`,
    IF(`cd`.`concert_date` <> '',
        DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d.%m.%Y'),
        NULL
    ) AS `concert_date`,
    TRIM(`cd`.`concert_time`) AS `concert_time`
FROM
    `categories` `c`
    JOIN `categories_description` `cd` ON `c`.`categories_id` = `cd`.`categories_id` 
WHERE
    `c`.`plan_id` > 2
 AND 
    `c`.`categories_status` = '1' 
 AND 
    `cd`.`categories_id` NOT IN(
    SELECT
        `p`.`parent_id`
    FROM
        `products` `p`
    WHERE
        `p`.`product_type` = 'X'
    AND
        `p`.`parent_id` = `cd`.`categories_id`
    GROUP BY `p`.`product_type`
) 
GROUP BY `c`.`categories_id`
ORDER BY DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%Y-%m-%d') DESC, `cd`.`categories_name` DESC

Inside this query I have one new filter what is added what looks like this: 在此查询中,我有一个新的过滤器,添加的内容如下所示:

 `cd`.`categories_id` NOT IN(
        SELECT
            `p`.`parent_id`
        FROM
            `products` `p`
        WHERE
            `p`.`product_type` = 'X'
        AND
            `p`.`parent_id` = `cd`.`categories_id`
        GROUP BY `p`.`product_type`
    )

I also try one more solution using NOT EXISTS but that is mutch worse: 我还尝试使用NOT EXISTS另一种解决方案,但这更糟糕了:

NOT EXISTS (
     SELECT
        DISTINCT 1
    FROM
        `products` `p`
    WHERE
        `p`.`product_type` = 'X'
    AND
        `p`.`parent_id` = `cd`.`categories_id`
    GROUP BY `p`.`product_type`
)   

My main problem is that after I add this filter for removing categories what contain X products, performances start to be realy bad. 我的主要问题是,在添加此过滤器以删除包含X产品的类别后,性能开始真的很差。 Without this filter page loading is arround 0.5-0.8 seconds but with this filter page load can be from 8 to 10 seconds. 如果没有此过滤器页面加载,则大约需要0.5-0.8秒,但使用此过滤器页面加载则可能需要8到10秒。

Can anyone help me to optimize this query? 谁能帮助我优化此查询?

This could work. 这可能有效。 Most engines aren't very good in NOT IN/NOT EXISTS, unless they internally modify the query to the form below. 大多数引擎的NOT IN / NOT EXISTS都不是很好,除非它们在内部将查询修改为以下形式。 At least it's worth a try. 至少值得一试。

SELECT
    `c`.`categories_id`,
    `c`.`section_id`,
    `c`.`categories_status`,
    IF(`c`.`categories_status` = 1, 'ON', 'OFF') AS `categories_status_name`,
    TRIM(`cd`.`categories_name`) AS `categories_name`,
    IF(`cd`.`concert_date` <> '',
        DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d.%m.%Y'),
        NULL
    ) AS `concert_date`,
    TRIM(`cd`.`concert_time`) AS `concert_time`
FROM
    `categories` `c` JOIN `categories_description` `cd` 
                     ON `c`.`categories_id` = `cd`.`categories_id`
     LEFT JOIN  `products` `p`
     ON `p`.`parent_id` = `cd`.`categories_id`
     AND `p`.`product_type` = 'X'
WHERE
    `c`.`plan_id` > 2
 AND 
    `c`.`categories_status` = '1' 
 AND 
    `p`.`parent_id` IS NULL 
GROUP BY `c`.`categories_id`
ORDER BY DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%Y-%m-%d') DESC, `cd`.`categories_name` DESC

Here is the most fastest solution I got. 这是我得到的最快的解决方案。

SELECT
    `c`.`categories_id`,
    `c`.`section_id`,
    `c`.`categories_status`,
    IF(`c`.`categories_status` = 1, 'ON', 'OFF') AS `categories_status_name`,
    TRIM(`cd`.`categories_name`) AS `categories_name`,
    IF(`cd`.`concert_date` <> '',
        DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%d.%m.%Y'),
        NULL
    ) AS `concert_date`,
    TRIM(`cd`.`concert_time`) AS `concert_time`
FROM
    `categories` `c`
    INNER JOIN `categories_description` `cd` ON `c`.`categories_id` = `cd`.`categories_id`
    LEFT JOIN `products` `p` ON `p`.`parent_id` = `cd`.`categories_id`
WHERE
    `c`.`plan_id` > 2
 AND 
    `c`.`categories_status` = '1'
 AND `p`.`product_type` != 'X'
GROUP BY `c`.`categories_id`
ORDER BY DATE_FORMAT(STR_TO_DATE(`cd`.`concert_date`,'%d/%m/%Y'),'%Y-%m-%d') DESC, `cd`.`categories_name` DESC

Thanks to @NigelRen who give me idea how to solve this problem. 感谢@NigelRen,他让我知道如何解决此问题。 @Ronald give almost same solution but is a bit slower (0.400 seconds) than my solution. @Ronald提供几乎相同的解决方案,但比我的解决方案要慢一些(0.400秒)。

Thank you guys for help! 谢谢大家的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM