Mysql 可以使用哪些索引来改进此查询?
此查询选择特定日期范围内的所有唯一访客会话:Mysql 可以使用哪些索引来改进此查询?,mysql,optimization,indexing,distinct,Mysql,Optimization,Indexing,Distinct,此查询选择特定日期范围内的所有唯一访客会话: select distinct(accessid) from accesslog where date > '2009-09-01' 我在以下字段上有索引: 访问ID 日期 其他一些领域 下面是解释的内容: mysql> explain select distinct(accessid) from accesslog where date > '2009-09-01'; +----+-------------+--------
select distinct(accessid) from accesslog where date > '2009-09-01'
我在以下字段上有索引:
- 访问ID
- 日期
- 其他一些领域
mysql> explain select distinct(accessid) from accesslog where date > '2009-09-01';
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
| 1 | SIMPLE | accesslog | range | date,dateurl,dateaff | date | 3 | NULL | 64623 | Using where; Using temporary |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
mysql> explain select distinct(accessid) from accesslog;
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
| 1 | SIMPLE | accesslog | index | NULL | accessid | 257 | NULL | 1460253 | Using index |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
为什么带有date子句的查询不使用accessid索引
在某些日期范围内,我是否可以使用其他索引来加速对不同accessid的查询
编辑分辨率
将accessid
上的列宽从varchar 255减少到char 32,将查询时间缩短了约75%
添加date+accessid
索引对查询时间没有影响
为什么带有date子句的查询不使用accessid索引
因为使用日期索引更有效。这是因为它可能会更快地缩减搜索空间
至少有一个DBMS(DB2/z,我对MySQL不太了解)会受益于date+accessid上的索引,因为访问ID将在该索引中的日期内排序。DBMS将使用date+accessid键有效地使用where子句缩减搜索空间,并在该空间内返回不同的accessid值
MySQL是否那么聪明,我不知道。我的建议是试试看(这是大多数DB优化问题的最佳答案)。查询使用“日期”索引,因为这是where子句中使用的 这是唯一明智的选择,如果它使用accessid索引,则需要读取所有accessid行,然后检查它之前的日期,然后才确定它是否不同
如果这是一个非常大的表,那么date和accessid上的复合索引可能会有所帮助。我没有办法测试它,但我肯定会尝试添加一个跨越accessid和date的索引
索引优化,如果经常像炼金术。不同的DBM表现不同,有时您需要简单地尝试(并失败)各种组合。我不是说不可能推理。在许多情况下是这样的,但在某种程度上是这样的。通常,遵循你的直觉更快更容易。你的问题是你的条件是一个范围子句(在日期列上) date->accessid的多列索引可能对这种情况没有帮助,因为MySQL不能在范围条件之后使用索引列。理论上,他们应该能够使用它来覆盖这种情况下的计算,但这似乎是MySQL的一个缺点,我从来没有在这种情况下成功地使用多列索引 您可以尝试在(date,accessid)上创建一个索引,希望它能够使用它来覆盖查询(这样您就不需要访问任何表),但我不抱太大希望。你能做的不多 编辑: 我的回答是有礼貌的,如果您必须进行认真的MySQL开发,那么它是值得的 为什么带有date子句的查询不使用accessid索引 因为使用日期索引可以忽略表中的大部分数据。很有可能,该表保存的大部分是历史数据,并且其中很多引用的日期比当前月初早得多,因此日期标准是有选择性的,允许优化器忽略大部分数据,从而减少了优化器的工作量 如果它使用accessid索引,它还必须读取每一行(以及每个索引条目),以查看日期是否符合搜索条件。这意味着读取整个索引和整个表——事实上,在上下文中忽略索引会更好,但我从“if it used the accessid index”开始 在某些日期范围内,我是否可以使用其他索引来加速对不同accessid的查询 根据优化器的复杂程度,索引(date,accessid)可能会有所改进。它可以在索引的前导列上进行范围搜索,尾随列意味着它不必引用表中的数据来建立accessid—信息在索引中。因此,这可能会将访问索引和表的查询转换为只访问索引的查询,这将减少所需的I/O量,从而提高查询的性能
如果您有其他条件需要来自其他列的数据,或者您需要返回的不仅仅是唯一的accessid值,那么您最终将读取部分表数据;与扫描整个表相比,这可能仍然是一个胜利。在
(日期,accessid)
上建立索引可能会有所帮助。但是,在调整索引之前,我建议检查accessid
列的类型EXPLAIN
说这个键有257字节长,这对于ID列来说似乎太多了。您是否使用VARCHAR(256)
作为accessid
?如果是这样,你就不能用一种更紧凑的字体吗?如果它是一个数字,它应该是INT
(SMALLINT
,BIGINT
,任何适合您需要的)如果它是一个字母数字ID,它真的可以是256个字符长吗?如果它的长度是固定的,你不能用CHAR
(例如CHAR(32)
)来代替吗?啊,好主意。我们使用的accessid是一个32个字符的字符串,例如94a1d523fac45e589e7d8884332fa9b3。我将缩小此字段的大小。是的,添加date+accessid索引没有任何效果。真倒霉