【问题标题】:how to make mysql derived table use index如何让mysql派生表使用索引
【发布时间】:2017-11-25 05:41:27
【问题描述】:

MySQL 版本 5.6.33

我有两个表(files & details)要进行内部连接

files,有一个名为idx_record(record_id)

的索引

details,有一个名为idx_end_org_record的索引(end_at, org_id, record_id)

explain
SELECT
    id as file_id,
    record_id,
    recording_path
FROM `files`
INNER JOIN
(
    SELECT `details`.`record_id`
    FROM `details` 
    WHERE `details`.`org_id` IN (6231, 6232, 6233, 6234) 
    AND (`details`.`end_at` BETWEEN '2017-05-31 16:00:00' AND '2017-06-13 16:00:00') 
    ORDER BY end_at desc
) as b
    on `files`.record_id = b.record_id 
WHERE (file_name IS NOT NULL )
LIMIT 30

输出如下

+----+-------------+--------------+-------+--------------------+--------------------+---------+------------------+---------+--------------------------+
| id | select_type | table        | type  | possible_keys      | key                | key_len | ref              | rows    | Extra                    |
+----+-------------+--------------+-------+--------------------+--------------------+---------+------------------+---------+--------------------------+
|  1 | PRIMARY     | <derived2>   | ALL   | NULL               | NULL               | NULL    | NULL             | 3844632 | Using where              |
|  1 | PRIMARY     | files        | ref   | idx_record         | idx_record         | 5       | b.record_id      |       1 | Using where              |
|  2 | DERIVED     | details      | range | idx_end_org_record | idx_end_org_record | 11      | NULL             | 3844632 | Using where; Using index |
+----+-------------+--------------+-------+--------------------+--------------------+---------+------------------+---------+--------------------------+

如您所见,&lt;derived2&gt; 表没有使用任何索引,这使得该查询需要将近 1 秒才能完成。

感谢任何帮助!


此外,在查询中删除 WHERE (file_name IS NOT NULL ) 没有任何区别。

而在 mysql 5.7 中,这个问题甚至不存在,但目前我正在尝试在 5.6 中解决这个问题。

【问题讨论】:

    标签: mysql derived-table


    【解决方案1】:

    我没有看到子查询的意义。特别是,子查询中的ORDER BY 毫无意义。如果您将查询编写为两个表之间的直接连接,那么优化器应该能够利用连接列上的索引:

    SELECT
    id as file_id,
    record_id,
    recording_path
    FROM files f
    INNER JOIN details d
        ON f.record_id = d.record_id AND
           d.org_id IN (6231, 6232, 6233, 6234) AND
           d.end_at BETWEEN '2017-05-31 16:00:00' AND '2017-06-13 16:00:00'
    WHERE f.file_name IS NOT NULL
    ORDER BY <some column>    -- it doesn't make sense most of the time to use LIMIT
    LIMIT 30                  -- without ORDER BY
    

    details 表中的record_idorg_idend_at 以及files 表中的file_name 上添加索引,应该会给您带来一些性能改进。

    【讨论】:

    • 请注意,没有 ORDER BY 的 LIMIT 是毫无意义的
    • @Strawberry 那我们在这里添加一些含义:-)
    • 1.这是一个内连接,所以子查询确实有意义:它不仅找出所有文件名不为空的文件,而且找出其详细信息符合某些条件的文件。
    • 2.感谢您的建议,但删除 ORDER BY 并没有多大帮助,只能节省 100 毫秒。我尝试更改索引中的列顺序,结果表详细信息中的 idx_end_org_record(org_id, end_at, record_id) 节省了近 300 毫秒。这两个索引之间的区别在于后者使解释输出中的rows 减少了10 倍。但是,&lt;derived2&gt; 表中仍然没有使用索引,使用索引会有意义,不是吗?
    • 您是否真的使用了我的完整答案,或者您只是对原始查询做了一些大杂烩?
    猜你喜欢
    • 2012-02-13
    • 2015-08-29
    • 1970-01-01
    • 2011-07-16
    • 2017-09-09
    • 2017-04-30
    • 2015-01-16
    • 1970-01-01
    • 2023-02-03
    相关资源
    最近更新 更多