【问题标题】:Query with OR making query execution SLOW使用 OR 进行查询,使查询执行缓慢
【发布时间】:2019-04-04 14:39:08
【问题描述】:

我是新手,在使用 OR 查询时遇到问题!

当我不使用 OR 时,执行时间为:0.02 秒

SELECT DISTINCT p.*,
                ht.html_title,
                ht.html_content,
                sc.sub_cat_name,
                sc.main_cat_id,
                us.username,
                c.name AS cityname
FROM   ad_product p,
       ad_html ht,
       ad_catagory_sub sc,
       ad_user us,
       ad_cities c
WHERE  ( ht.ad_id = p.id )
       AND ( sc.sub_cat_id = p.category )
       AND ( us.id = p.user_id )
       AND ( p.category = 216 )
       AND ( p.status = 'active' )
       AND ( c.id = p.city )
       AND ( p.city = 135 )
ORDER  BY p.created_at DESC;

当我尝试使用 OR 条件时,大约需要 4.70 秒

SELECT DISTINCT p.*,
                ht.html_title,
                ht.html_content,
                sc.sub_cat_name,
                sc.main_cat_id,
                us.username,
                c.name AS cityname
FROM   ad_product p,
       ad_html ht,
       ad_catagory_sub sc,
       ad_user us,
       ad_cities c
WHERE  ( ht.ad_id = p.id )
       AND ( sc.sub_cat_id = p.category )
       AND ( us.id = p.user_id )
       AND ( p.category = 216
              OR p.parent_category = 216 )
       AND ( p.status = 'active' )
       AND ( c.id = p.city )
       AND ( p.city = 135 )
ORDER  BY p.created_at DESC;

解释:

+----+-------------+-------+------------+-------------+--------------------------------------------------------------------------------+--------------------------+---------+---------------------------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type        | possible_keys                                                                  | key                      | key_len | ref                       | rows  | filtered | Extra                                              |
+----+-------------+-------+------------+-------------+--------------------------------------------------------------------------------+--------------------------+---------+---------------------------+-------+----------+----------------------------------------------------+
|  1 | SIMPLE      | c     | NULL       | const       | PRIMARY                                                                        | PRIMARY                  | 4       | const                     |     1 |   100.00 | Using temporary; Using filesort                    |
|  1 | SIMPLE      | p     | NULL       | index_merge | PRIMARY,id,parent_category,city,user_id_2,category,status,id_2,id_3,category_2 | category,parent_category | 4,4     | NULL                      | 67889 |     4.74 | Using union(category,parent_category); Using where |
|  1 | SIMPLE      | sc    | NULL       | eq_ref      | PRIMARY                                                                        | PRIMARY                  | 4       | abc_classified.p.category |     1 |   100.00 | NULL                                               |
|  1 | SIMPLE      | us    | NULL       | eq_ref      | PRIMARY                                                                        | PRIMARY                  | 4       | abc_classified.p.user_id  |     1 |   100.00 | NULL                                               |
|  1 | SIMPLE      | ht    | NULL       | ref         | ad_id                                                                          | ad_id                    | 4       | abc_classified.p.id       |     1 |   100.00 | NULL                                               |
+----+-------------+-------+------------+-------------+--------------------------------------------------------------------------------+--------------------------+---------+---------------------------+-------+----------+----------------------------------------------------+

我想我已经定义了正确的索引,有人可以指出我做错了什么吗?或者我怎样才能减少执行时间?另外,据我所知,为什么会发生这种情况?

【问题讨论】:

  • 请将您的查询格式化为多行,以便我们阅读。
  • union 解决方案应该可以工作,顺便说一句,您可以调用两个表 p,无需将顶部查询更改为 p1。

标签: mysql sql performance conditional-statements


【解决方案1】:

当您在 where 条件中定义精确值时,SQL 使用 hash join。所以它比其他连接快得多。当您将其更改为非精确值条件( X OR Y )时,它会变慢。

解决方法是创建一个index,以减少要搜索的记录。

【讨论】:

  • 我已经在 "category" 和 parent_category 上分别定义了索引。请看一下我发布的 EXPLAIN 结果,它表明带有“OR”的查询已经在使用索引。
【解决方案2】:

我认为您的查询将受益于联合而不是或。 这将创建 2 组数据。一个在 categoryid 上,另一个在父 categoryid 上。这将比定义 2 个负集更快。一组没有 categoryid = 216,一组没有父 categoryid = 216。

SELECT DISTINCT p1.*,
        ht.html_title,
        ht.html_content,
        sc.sub_cat_name,
        sc.main_cat_id,
        us.username,
        c.name AS cityname
FROM   ad_product p1 inner join ad_html ht on ht.ad_id = p1.id
    inner join ad_category_sub sc on sc.sub_cat_id = p1.category
    inner join ad_user us on  us.id = p1.user_id 
    inner join ad_cities c on c.id = p1.city   
WHERE ( p1.status = 'active' )
   AND ( p1.city = 135 )
   AND ( p1.category = 216)
UNION
SELECT DISTINCT p.*,
        ht.html_title,
        ht.html_content,
        sc.sub_cat_name,
        sc.main_cat_id,
        us.username,
        c.name AS cityname
FROM   ad_product p 
    inner join ad_html ht on ht.ad_id = p.id
    inner join ad_category_sub sc on sc.sub_cat_id = p.category
    inner join ad_user us on us.id = p.user_id
    inner join ad_cities c on c.id = p.city
WHERE ( p.status = 'active' )
  AND ( p.city = 135 )
  AND (p.parent_category = 216)
ORDER  BY p.created_at DESC;

【讨论】:

  • Reynoldson 感谢您的回答。我尝试执行查询并得到一个错误:“#1250 - 来自其中一个 SELECT 的表 'p' 不能在字段列表中使用”我不明白它在说什么,也许你能帮忙!
  • 嗨 Aarav,我认为该错误是由查询的上半部分和下半部分使用的相同别名“p”引起的。我在代码示例中编辑了查询,以便在上半部分使用“p1”。试试看,让我知道你是怎么过的。如果仍然不满意,我需要构建您的数据结构的迷你版本来测试查询。
  • 嗨 Reynoldson,感谢您的编辑,但它给出了相同的错误“#1250 - 来自 SELECT 之一的表 'p' 不能在字段列表中使用”我什至尝试将 p 更改为 p2 但是没有运气。
  • 嗨 Aarav,我再次编辑了代码块。这对我来说没有错误(我正在使用测试数据结构,这是用 SQL 服务器编写的,因此如果您使用 mysql,可能需要转换为 mysql)。我基本上已经用连接替换了大部分 where 子句(这是优化器无论如何都会做的),并且我仍在使用联合来避免 or 运算符问题。我希望这能让你更接近。
  • 嘿 Reynoldson,感谢您提供的优化解决方案。它有效,但没有“ORDER BY”,因为它抛出了相同的“#1250”错误。经过一段时间的搜索,我得到了bugs.mysql.com/bug.php?id=68529,这表明当我们将“ORDER BY”与 UNION 或 GROUP BY 一起使用时存在一些错误。我仍在使用 ORDER BY 寻找解决方案,但这可以。非常感谢您的帮助!
【解决方案3】:

@Dwight Reynoldson Answers 在 SQL Server 上工作得很好,我得到了 MySQL 上“ORDER BY”问题的解决方法。我所做的只是ORDER BY created_at DESC 而不是ORDER BY p.created_at DESC 这是造成所有问题的p。

答案:

SELECT DISTINCT p1.*,
        ht.html_title,
        ht.html_content,
        sc.sub_cat_name,
        sc.main_cat_id,
        us.username,
        c.name AS cityname
FROM   ad_product p1 inner join ad_html ht on ht.ad_id = p1.id
    inner join ad_category_sub sc on sc.sub_cat_id = p1.category
    inner join ad_user us on  us.id = p1.user_id 
    inner join ad_cities c on c.id = p1.city   
WHERE ( p1.status = 'active' )
   AND ( p1.city = 135 )
   AND ( p1.category = 216)
UNION
SELECT DISTINCT p.*,
        ht.html_title,
        ht.html_content,
        sc.sub_cat_name,
        sc.main_cat_id,
        us.username,
        c.name AS cityname
FROM   ad_product p 
    inner join ad_html ht on ht.ad_id = p.id
    inner join ad_category_sub sc on sc.sub_cat_id = p.category
    inner join ad_user us on us.id = p.user_id
    inner join ad_cities c on c.id = p.city
WHERE ( p.status = 'active' )
  AND ( p.city = 135 )
  AND (p.parent_category = 216)
ORDER BY created_at DESC;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-10
    • 2020-04-23
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 2013-11-06
    • 2010-10-27
    相关资源
    最近更新 更多