【问题标题】:What indexes can be used to improve this query?可以使用哪些索引来改进此查询?
【发布时间】:2009-09-11 05:48:45
【问题描述】:

此查询选择特定日期范围内的所有唯一访问者会话:

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 |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+

为什么带有日期子句的查询不使用accessid索引?

是否有任何其他索引可以用来加快在特定日期范围内对不同 accessid 的查询?

编辑 - 分辨率

accessid 上的列宽从 varchar 255 减少到 char 32 将查询时间缩短了约 75%。

添加date+accessid 索引对查询时间没有影响。

【问题讨论】:

    标签: mysql optimization indexing distinct


    【解决方案1】:

    (date,accessid) 上的索引可以提供帮助。但是,在调整索引之前,我建议您检查 accessid 列的类型。 EXPLAIN 表示密钥长度为 257 字节,这对于 ID 列来说听起来很多。您是否将VARCHAR(256) 用于accessid?如果是这样,你不能使用更紧凑的类型吗?如果它是一个数字,它应该是INTSMALLINTBIGINT,任何适合您的需要),如果它是一个字母数字 ID,它真的可以是 256 个字符吗?如果它的长度是固定的,你不能用CHAR(例如CHAR(32))来代替吗?

    【讨论】:

    • 啊,好电话。我们使用的 accessid 是一个 32 个字符的字符串,例如 94a1d523fac45e589e7d8884332fa9b3。我会缩小这个字段的大小。
    【解决方案2】:

    您的问题是您的条件是范围子句(在日期列上)。

    date->accessid 的多列索引可能对这种情况没有帮助,因为 MySQL 不能在范围条件之后使用索引列。理论上他们应该能够使用它来覆盖这种情况下的计算,但这似乎是 MySQL 的一个缺点,我从来没有成功地在这种情况下使用多列索引。

    您可以尝试在 (date,accessid) 上创建一个索引,希望它会使用它来覆盖查询(这样您就不需要点击任何表),但我不抱太大希望。你无能为力。

    编辑:

    我的回答是由High Performance MySQL - Second Edition 提供的,如果您必须进行认真的 MySQL 开发,那么它是金子般的重量。

    【讨论】:

    • 是的,添加日期+accessid 索引没有效果。无赖。
    【解决方案3】:

    为什么有date子句的查询不使用accessid索引?

    因为使用日期索引更有效。那是因为它可能会更快地减少搜索空间。

    至少一个 DBMS(DB2/z,我对 MySQL 了解不多)会受益于 date+accessid 上的索引,因为访问 ID 将在该索引中的日期内排序。该 DBMS 将使用 date+accessid 键有效地使用 where 子句缩减搜索空间以返回该空间内不同的 accessid 值。

    MySQL 是否那么聪明,我不知道。我的建议是尝试一下(这是大多数数据库优化问题的最佳答案)。

    【讨论】:

      【解决方案4】:

      查询使用“日期”索引,因为那是您在 where 子句中使用的索引。

      这是唯一明智的选择,如果它使用访问 ID 索引,则需要读取所有访问 ID 行,然后检查它之前的日期,然后才确定它是否不同。

      如果这是一个非常大的表,日期和 accessid 的复合索引可能会有所帮助。

      【讨论】:

        【解决方案5】:

        为什么带有date子句的查询不使用accessid索引?

        因为使用日期索引可以让它忽略表中的大部分数据。有可能该表主要包含历史数据,其中很多是指比当前月初更早的日期,因此日期标准是有选择性的,并允许优化器忽略大多数数据,从而减少了优化器的工作量数据。

        如果它使用 accessid 索引,它还必须读取每一行(以及每个索引条目)以查看日期是否符合搜索条件。这意味着读取整个索引和整个表 - 事实上,在上下文中忽略索引会更好,但我从“如果它使用 accessid 索引”开始。

        是否有任何其他索引可以用来加快在特定日期范围内对不同 accessid 的查询?

        根据优化器的复杂程度,(date, accessid) 上的索引可能会有所改善。它可以对索引的前导列进行范围搜索,而尾随列意味着它不必引用表中的数据来建立accessid——信息在索引中。因此,这可能会将访问索引和表的查询转换为仅访问索引的查询 - 这将减少所需的 I/O 量,从而提高查询的性能。

        如果您有其他条件需要来自其他列的数据,或者您需要返回的不仅仅是唯一的 accessid 值,那么您最终会读取部分表数据;与扫描整个表格相比,这可能仍然是一个胜利。

        【讨论】:

          【解决方案6】:

          我无法对其进行测试,但我肯定会尝试添加一个跨越 accessid 和日期的索引

          如果经常像炼金术一样进行索引优化。不同的 DBMS 表现不同,有时您需要简单地尝试(并失败)各种组合。我并不是说不可能推理。在很多情况下是这样,但在一定程度上是这样。通常,跟随你的直觉会更快更容易。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-31
            • 1970-01-01
            相关资源
            最近更新 更多