【问题标题】:Help with performance: SUBQUERY vs JOIN性能帮助:SUBQUERY vs JOIN
【发布时间】:2011-10-30 08:50:06
【问题描述】:

这是我的问题:

子查询2.7 secs

SELECT SQL_NO_CACHE 
  item_id

  FROM
    mtrt_items_searches

  WHERE
    search_id IN (      
            SELECT 
            SQL_NO_CACHE
                search_id
                FROM
                    mtrt_searches_groups
                WHERE 
                    client_id =1
                GROUP BY 
                    search_id

        )

    LIMIT 0,350000

+----+--------------------+----------------------+-------+---------------+-----------+---------+-------+--------+--------------------------+
| id | select_type        | table                | type  | possible_keys | key       | key_len | ref   | rows   | Extra                    |
+----+--------------------+----------------------+-------+---------------+-----------+---------+-------+--------+--------------------------+
|  1 | PRIMARY            | mtrt_items_searches  | index | NULL          | search_id | 12      | NULL  | 367362 | Using where; Using index |
|  2 | DEPENDENT SUBQUERY | mtrt_searches_groups | ref   | client_id     | client_id | 4       | const |     13 | Using where; Using index |
+----+--------------------+----------------------+-------+---------------+-----------+---------+-------+--------+--------------------------+

仅子查询需要 0.0009 秒才能返回以下数据,并将子查询替换为该数据,查询运行在0.2 secs

SELECT SQL_NO_CACHE
    item_id

    FROM
        mtrt_items_searches
    WHERE
        search_id IN (
            1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35
        )

    LIMIT 0,350000

+----+-------------+---------------------+-------+---------------+-----------+---------+------+--------+--------------------------+
| id | select_type | table               | type  | possible_keys | key       | key_len | ref  | rows   | Extra                    |
+----+-------------+---------------------+-------+---------------+-----------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | mtrt_items_searches | index | search_id     | search_id | 12      | NULL | 367362 | Using where; Using index |
+----+-------------+---------------------+-------+---------------+-----------+---------+------+--------+--------------------------+

终于运行在0.4 secs的JOIN:

   SELECT SQL_NO_CACHE
        r.item_id

        FROM
            mtrt_items_searches r
        INNER JOIN 
            mtrt_searches_groups sg 
                ON r.search_id =sg.search_id
        WHERE 
            sg.client_id =1
        GROUP BY 
            r.item_id

        LIMIT 0,350000

+----+-------------+-------+------+---------------------+-----------+---------+------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys       | key       | key_len | ref                    | rows  | Extra                                        |
+----+-------------+-------+------+---------------------+-----------+---------+------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | sg    | ref  | search_id,client_id | client_id | 4       | const                  |    13 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | r     | ref  | search_id           | search_id | 4       | clubr_new.sg.search_id | 26240 | Using index                                  |
+----+-------------+-------+------+---------------------+-----------+---------+------------------------+-------+----------------------------------------------+

我正在尝试在0.2 secs 中执行子查询或联接。有可能吗?

【问题讨论】:

  • 重新启动 MySql 并再次使用硬编码的 ID 运行第二个查询。这将需要接近 5 秒。 (SQL_NO_CACHE 不考虑 OS 文件缓存)
  • 尝试进行选择并指定表名。在第一个选择(带有子查询)中,我看到您使用相同的列名,但我不确定它们如何在子查询中得到解决。不知道这会如何影响事情
  • 我们在这里讨论了多少条记录?
  • @Doug-Kress 约 350000
  • @the-scrum-meister 我已经测试过了。同一时间。

标签: mysql performance join subquery


【解决方案1】:

尝试以下查询:

SELECT STRAIGHT_JOIN item_id
FROM (
    SELECT DISTINCT search_id
    FROM mtrt_searches_groups
    WHERE client_id = 1
) JOIN mtrt_items_searches USING(search_id)
LIMIT 0,350000

【讨论】:

  • 太棒了。 0.2 secs。不知道mysql其实没有STRAIGHT_JOIN就不会先执行子查询。那么,子查询比连接快吗?
  • @Doug-Kress 和“The Scrum Meister”:没有 STRAIGHT_JOIN 实际上运行方式相同。主要变化来自子查询位置。
【解决方案2】:

嗯,我不这么认为。子查询太慢了,可惜最快的方法是直接使用数据。

【讨论】:

    【解决方案3】:

    尝试添加以下索引

    mtrt_items_searches(search_id,item_id)
    mtrt_searches_groups(client_id, search_id)
    

    【讨论】:

    • 查看最后一个 SELECT 的解释;)
    • @Downvoter 请发表评论。从EXPLAIN 输出中可以看出,search_id,item_id 上没有 composite 索引
    • @他为什么需要复合索引来进行直接搜索?同时搜索两个键时使用复合索引。在最后一个 EXPLAIN 中,所有项目都使用索引列,结果完全返回 LIMIT 语句中请求的行数。一切似乎都很好那里。也许服务器/网络有太多行来处理它们
    • +1 谢谢!我已经改变了这一点。我仍在努力最终实现0.2 secs。再看一遍。
    • @Keyne 更改对结果有何影响?
    猜你喜欢
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    相关资源
    最近更新 更多