普通网友 2017-11-27 04:44
浏览 69

如何通过NOT IN或NOT EXISTS过滤MySQL Query中的性能

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 (
     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. 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.

Can anyone help me to optimize this query?

展开全部

  • 写回答

2条回答

  • dongxie8906 2017-11-27 04:54
    关注

    This could work. Most engines aren't very good in NOT IN/NOT EXISTS, unless they internally modify the query to the form below. 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
    
    评论
  • douying1119 2017-11-27 05:06
    关注

    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. @Ronald give almost same solution but is a bit slower (0.400 seconds) than my solution.

    Thank you guys for help!

    评论
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部