提高MySQL选择查询的执行速度
我有两个MySQL表,其中有数百万行,我正在尝试对这两个表中的get-specific-data列执行查询选择。尽管我的第一个良好预期是,查询选择的执行也需要几秒钟(大约5秒钟)的时间,索引也应用于WHERE条件 为2个MySQL表创建语句: 如您所见,这两个表都有一个AI主键和外键,它们之间匹配为提高MySQL选择查询的执行速度,mysql,database,performance,select,query-performance,Mysql,Database,Performance,Select,Query Performance,我有两个MySQL表,其中有数百万行,我正在尝试对这两个表中的get-specific-data列执行查询选择。尽管我的第一个良好预期是,查询选择的执行也需要几秒钟(大约5秒钟)的时间,索引也应用于WHERE条件 为2个MySQL表创建语句: 如您所见,这两个表都有一个AI主键和外键,它们之间匹配为一对一关系(T1\u id和T2\u id)。我们有一个索引应用于T1,用于T1_val4的日期时间格式 选择查询 正如您所注意到的,我为索引指定了一个提示,以便告诉MySQL对datetime列使用
一对一关系
(T1\u id
和T2\u id
)。我们有一个索引应用于T1
,用于T1_val4
的日期时间格式
选择查询
正如您所注意到的,我为索引指定了一个提示,以便告诉MySQL对datetime列使用该特定索引。实际上,如果我将WHERE条件下的datetime范围扩展到几个小时。。例如,在“2016-02-18 15:00:00”和“2016-02-18 23:59:59”之间执行时间增长到50/100秒。也许我在逻辑上遗漏了什么
解释输出
EXPLAIN输出用复合索引更新
(根据@O.Jones的建议)
ix_rlf是T1_val4
,T1_val9
,T1_val5
,ix_cc是@Tom Shir为T2建议的复合索引,由T2_id
,T2_val1
,T2_val2
,T2_val3
组成
查询执行计划可视化模式
(以2小时为间隔,在本例中,查询结果约为6632行,执行时间为6/7秒)
从您的GROUP By
子句中省略T1_val4
就是在利用MySQL的非标准扩展。你可能会得到不想要的结果。请看这个
通常,对类似日期时间的列使用BETWEEN
是个坏主意,因为它处理范围结束条件很差。如果我是你,我会写这个
WHERE T1_val4 >= '2016-02-18 15:00:00' AND T1_val4 < '2016-02-18 17:00:00'
因为您使用的是InnoDB,所以不必在复合索引中包含主键
这应该快一点。但是,您仍然要求MySQL检索和索引一万行,这实际上是真正的工作。这是您的带有表前缀的查询:
SELECT
T1.T1_val5,
T2.T2_val1,
T2.T2_val2,
T2.T2_val3,
T1.T1_val9,
COUNT(T2.T2_val1) AS cnt,
T1.T1_val4
FROM
T1
INNER JOIN
T2.T2
ON T1.T1_id = T2.T2_id
WHERE
T1.T1_val4 BETWEEN '2016-02-18 15:00:00' AND '2016-02-18 16:59:59'
GROUP BY
T2.T2_val1,
T2.T2_val2,
T2.T2_val3,
T1.T1_val9,
T1.T1_val5
ORDER BY
T1.T1_val4 ASC
我相信您可以通过使用正确的索引来提高其性能。
我通过一个用于我自己的查询的数据库运行了您的查询,该数据库建议使用以下索引:
ALTER TABLE `T1` ADD INDEX `T1_index_1` (`T1_id`, `T1_val4`);
ALTER TABLE `T2` ADD INDEX `T2_index_1` (`T2_id`, `T2_val1`, `T2_val2`, `T2_val3`);
另外,请发布解释计划,因为它可以帮助更好地理解MySQL当前使用的索引
另一个建议-删除您添加的提示。通常,MySQL会比我们更了解如何优化查询。请阅读本文,请特别注意有关查询性能的部分。请您的问题向我们展示解释
输出和其他相关信息。顺便说一句,您的分组依据
子句还需要提到T1_val4
,您的邮戳栏。您说得对!给我几分钟,我将添加解释输出。innodb\u buffer\u pool\u size的值是多少?您有多少RAM?对于innodb\u buffer\u pool\u size
而言,它是6123683840请注意,ix\u cc
未被选中。无论如何,PRIMARY
也差不多。谢谢@O.Jones的回复。我正在阅读我收到的两个答案。你能确切地解释一下为什么只索引T1
应该比@Tom Shir写的T2
更好吗?在性能方面应该略有不同?我已经尝试添加了您为T1
建议的复合索引,我已经替换了中间条件,并且我还将T1\u val4
纳入了组中。但是在这些更改之后,执行性能保持不变。我不建议索引T2
,因为您的EXPLAIN
输出表示您的查询只查看了几行,而且您通过其主键访问它,并且没有WHERE
条件。添加复合索引后,解释
会告诉你什么?更好的是:其中T1_val4>='2016-02-18 15:00:00'和T1_val4<'2016-02-18 15:00:00'+间隔2小时
@UgoL-间隔
模式对性能没有帮助-一定是同时发生了其他事情。(10倍的加速通常可以追溯到缓存。)fwiw,对于优化T1_val4
上范围扫描的索引,该列必须位于索引列列表的第一位。此外,在InnoDB中,主键位于第一位的索引与表本身的结构是冗余的。您能否解释一下为什么范围列应该位于第一位(可能还包括一个引用链接)?如果是这种情况,那么这意味着您不能创建一个索引,其中ON子句中的列和范围扫描都将用于优化同一查询?是理解查询优化的好资源。MySQL索引具有有序的BTREE结构。因此,当查询调用某列中的连续值范围时,如果该列位于第一列,则查询计划器可以随机访问第一个符合条件的条目的索引,然后按顺序扫描到最后一个条目。谢谢。我已经阅读了过去的那些文章,看到这个页面指定先为相等设置索引,然后才为范围设置索引。当等式为col1=col2(就像通常在join-ON子句中发生的那样)而不是col1=const时,情况会有所不同吗?
+-------+---------------+-----------+-----------+------------------------------+-----------+---------------+-----------+-----------+---------------------------------------------------------------+
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
+-------+---------------+-----------+-----------+------------------------------+-----------+---------------+-----------+-----------+---------------------------------------------------------------+
| 1 | SIMPLE | T1 | range | "PRIMARY,ix_rlf" | ix_rlf | 5 | NULL | 10906 | "Using where; Using index; Using temporary; Using filesort" |
+-------+---------------+-----------+-----------+------------------------------+-----------+---------------+-----------+-----------+---------------------------------------------------------------+
| 1 | SIMPLE | T2 | eq_ref | "PRIMARY,ix_cc" | PRIMARY | 4 | T1_id | 1 | NULL |
+-------+---------------+-----------+-----------+------------------------------+-----------+---------------+-----------+-----------+---------------------------------------------------------------+
WHERE T1_val4 >= '2016-02-18 15:00:00' AND T1_val4 < '2016-02-18 17:00:00'
T1_val4, T1_val9, T1_val5
SELECT
T1.T1_val5,
T2.T2_val1,
T2.T2_val2,
T2.T2_val3,
T1.T1_val9,
COUNT(T2.T2_val1) AS cnt,
T1.T1_val4
FROM
T1
INNER JOIN
T2.T2
ON T1.T1_id = T2.T2_id
WHERE
T1.T1_val4 BETWEEN '2016-02-18 15:00:00' AND '2016-02-18 16:59:59'
GROUP BY
T2.T2_val1,
T2.T2_val2,
T2.T2_val3,
T1.T1_val9,
T1.T1_val5
ORDER BY
T1.T1_val4 ASC
ALTER TABLE `T1` ADD INDEX `T1_index_1` (`T1_id`, `T1_val4`);
ALTER TABLE `T2` ADD INDEX `T2_index_1` (`T2_id`, `T2_val1`, `T2_val2`, `T2_val3`);