此查询选择特定日期范围内的所有唯一身份访问者会话:
select distinct(accessid) from accesslog where date > '2009-09-01'
我在以下字段中有索引:
以下是解释:
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
索引对查询时间没有影响。
答案 0 :(得分:5)
(date,accessid)
上的索引可以帮助。但是,在调整索引之前,我建议您检查accessid
列的类型。 EXPLAIN
表示密钥长度为257字节,对于ID列来说听起来很多。您是否使用VARCHAR(256)
accessid
?如果是这样,你不能使用更紧凑的类型吗?如果它是一个数字,它应该是INT
(SMALLINT
,BIGINT
,符合您的需要),如果它是一个字母数字ID,它真的是256 chars多长?如果其长度是固定的,您不能使用CHAR
(例如CHAR(32)
)吗?
答案 1 :(得分:2)
您的问题是您的条件是范围子句(在日期列上)。
date-> accessid的多列索引可能无法帮助解决这种情况,因为MySQL在范围条件之后无法使用索引列。从理论上讲,它们应该能够用它来覆盖这种情况下的计算,但它似乎是MySQL的一个缺点,我从来没有在这种情况下成功地使用多列索引。
你可以尝试在(date,accessid)上创建一个索引,希望它能用它来覆盖查询(所以你不需要点击任何表格),但我没有太大的希望。你可以做的不是很多。
编辑:
我的回答是High Performance MySQL - Second Edition的礼貌,如果你不得不进行严肃的MySQL开发,那么它的重要性就是黄金。
答案 2 :(得分:0)
为什么带有date子句的查询不使用accessid索引?
因为使用日期索引更有效率。那是因为它可能会更快地削减搜索空间。
至少有一个DBMS(DB2 / z,我对MySQL不太了解)会受益于date + accessid上的索引,因为访问ID将在该索引的日期内排序。 DBMS将使用date + accessid键有效地使用where子句来缩小搜索空间和,以在该空间内返回accessid的不同值。
MySQL是否聪明,我不知道。我的建议是尝试一下(这是大多数数据库优化问题的最佳答案)。
答案 3 :(得分:0)
查询使用'date'索引,因为这就是你在where子句中使用的内容。
这是唯一明智的选择,如果它使用了访问id索引,它需要读取所有accessid行,然后检查它之前的日期,然后才决定它是否是不同的。
如果这是一张非常大的表,那么日期和accessid上的复合索引可能有所帮助。
答案 4 :(得分:0)
我无法对其进行测试,但我绝对会尝试添加一个跨越accessid和date 的索引。
索引优化(如果经常喜欢炼金术)。不同的DBMS行为不同,有时您只需尝试(并失败)各种组合。我不是说不可能推理。在许多情况下,但达到某一点。通常,只需更快,更容易地遵循你的直觉。
答案 5 :(得分:0)
为什么带有date子句的查询不使用accessid索引?
因为使用日期索引允许它忽略表中的大部分数据。很可能该表主要包含历史数据,其中很多都是指比当前月初更早的日期,因此日期标准是选择性的,通过允许它忽略大多数来减少优化程序的工作量数据。
如果它使用了accessid索引,则还必须读取每一行(以及每个索引条目)以查看日期是否符合搜索条件。这意味着读取整个索引和整个表 - 实际上,在上下文中忽略索引会做得更好,但我开始使用“如果它使用了accessid索引”。
我是否可以使用其他索引来加快某些日期跨度中不同accessid的查询?
根据优化程序的复杂程度,(date,accessid)上的索引可能会改进。它可以在索引的前导列上进行范围搜索,尾随列表示它不必引用表中的数据来建立accessid - 信息在索引中。因此,这可能会将访问索引和表的查询转换为仅访问索引的查询 - 这将减少所需的I / O量,从而提高查询的性能。
如果您有其他标准需要来自其他列的数据,或者您需要返回的不仅仅是唯一的accessid值,那么您最终会读取部分表数据;与扫描整个表格相比,这可能仍然是一个胜利。