【问题标题】:Is index dependent on selected columns?索引是否依赖于选定的列?
【发布时间】:2013-03-20 10:33:27
【问题描述】:

我正在根据时间执行大部分查询。所以我为创建时间创建了索引。但是,只有索引才有效,如果我只选择索引列。 mysql索引是否依赖于选定的列?

我对索引的假设

我认为索引就像电话词典索引页。例如:如果我想找到“Mark”。索引页显示目录中哪个页字符“M”开始。我认为和mysql一样。

表格

+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| ID           | int(11)      | NO   | PRI | NULL    | auto_increment |
| Name         | varchar(100) | YES  |     | NULL    |                |
| OPERATION    | varchar(100) | YES  |     | NULL    |                |
| PID         | int(11)      | YES  |     | NULL    |                |
| CREATED_TIME | bigint(20)   | YES  |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

表上的索引。

    +-----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| IndexTest |          0 | PRIMARY  |            1 | ID           | A         |       10261 |     NULL | NULL   |      | BTREE      |         |               |
| IndexTest |          1 | t_dx     |            1 | CREATED_TIME | A         |         410 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

使用索引的查询:

   explain select * from IndexTest where ID < 5;
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | IndexTest | range | PRIMARY       | PRIMARY | 4       | NULL |    4 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+



  explain select CREATED_TIME from IndexTest where CREATED_TIME > UNIX_TIMESTAMP(CURRENT_DATE())*1000;
    +----+-------------+-----------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
+----+-------------+-----------+-------+---------------+------+---------+------+------+--------------------------+
|  1 | SIMPLE      | IndexTest | range | t_dx          | t_dx | 9       | NULL | 5248 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+------+--------------------------+

不使用索引的查询

    explain select count(distinct(PID)) from IndexTest where CREATED_TIME > UNIX_TIMESTAMP(CURRENT_DATE())*1000;
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | IndexTest | ALL  | t_dx          | NULL | NULL    | NULL | 10261 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+


    explain select PID from IndexTest where CREATED_TIME > UNIX_TIMESTAMP(CURRENT_DATE())*1000;
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | IndexTest | ALL  | t_dx          | NULL | NULL    | NULL | 10261 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+-------+-------------+

【问题讨论】:

  • 索引有助于加快对特定列和相关数据而非表数据的搜索。所以你必须包含索引列来加速select

标签: mysql


【解决方案1】:

简答:否。

是否使用索引取决于WHERE 子句、JOINs 等中的表达式,而不取决于您选择的列。

但没有规则没有例外(或者实际上是一长串):

长答案:通常不会

MySQL 优化器使用了许多因素来确定它是否应该使用索引。

如果……,优化器可能会决定忽略索引

  • 另一个(否则不是最佳的)将其完全避免访问表数据
  • 无法理解表达式是常量
  • 它的估计表明它无论如何都会返回完整的表格
  • 如果使用它会导致创建临时文件
  • ...还有很多其他原因,其中一些似乎没有记录在任何地方

有时,所述优化器所做的选择是……呃……让我们称它们为次优。现在在这些情况下你会怎么做?

  • 您可以通过OPTIMIZE TABLE 和/或ANALYZE TABLE 帮助优化器。这很容易做到,而且有时会有所帮助。
  • 您可以通过USE INDEX(indexname)FORCE INDEX(indexname) 语法使其使用某个索引
  • 您可以使用IGNORE INDEX(indexname) 语法使其忽略某个索引

有关Index HintsOptimize TableAnalyze Table 的更多详细信息,请访问 MySQL 文档网站。

【讨论】:

    【解决方案2】:

    其实,你是否选择该列并没有什么区别。索引用于查找,这意味着快速减少您需要检索的记录数量。这使得它通常在以下情况下很有用:你有连接,你有 where 条件。索引也有助于排序。

    在 where 条件下使用索引也可以大大加快更新和删除的速度。

    举个例子:

    table: id int pk ai, col1 ... indexed, col2 ...
    select * from table -> does not use a index
    select id from table where col1 = something -> uses the col1 index although it is not selected.
    

    看第二个查询,mysql在索引中查找,找到记录,然后在这种情况下停止并交付(id和col1都有索引,id恰好是pk,所以不需要二次查找) .

    在这种情况下情况略有变化:

    select col2 from table where col1 = something
    

    这将在内部进行 2 次查找:1 次用于条件,1 次在 pk 上用于传递 col2 数据。请再次注意,您无需选择 col1 列即可使用索引。

    回到您的查询,问题出在:UNIX_TIMESTAMP(CURRENT_DATE())*1000; 如果您删除它,您的索引将用于查找。

    【讨论】:

    • 他在 col CREATED_TIME 的问题中有第二个索引,您引用的值是 where 子句检查此列且仅此列的一部分。第二个索引不应该用于该查询吗?看来它至少应该是合格的,也许这里关于查询计划器的另一个讨论是问题所在。
    【解决方案3】:

    mysql 索引是否依赖于选定的列?

    是的,绝对的。

    对于example

    如果列不形成最左边,MySQL 不能使用索引来执行查找 索引的前缀。假设您有此处显示的 SELECT 语句:

    SELECT * FROM tbl_name WHERE col1=val1;
    SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
    
    SELECT * FROM tbl_name WHERE col2=val2;
    SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
    

    如果(col1, col2, col3) 上存在索引,则只有前两个查询使用该索引。 第三和第四个查询确实涉及索引列,但(col2)(col2, col3) 不是(col1, col2, col3) 的最左边前缀。

    阅读the extensive documentation

    【讨论】:

    • SELECT * FROM tbl_name WHERE col1=val1;.此选择查询获取表中的五列。但是,它不是最左边的前缀,而是索引在此处的使用方式。此查询使用 index 。解释 select * from IndexTest where ID
    • @bharathi:优化器可能正在发挥作用,尤其是当您 [似乎] 有这么少的行时。试图为这种行为合理化往往是徒劳的。
    • 谢谢。 “试图为这种行为合理化往往是愚蠢的差事”。我们如何在不理解的情况下编写查询。
    • @bharathi 你可以很好地理解这个查询。您可以遵循文档中列出的索引规则。当优化器有时允许查询执行比预期的更好时,请不要感到惊讶。
    • 我从来不知道。我刚刚用 EXPLAIN 再次确认。
    【解决方案4】:

    对于mysql查询,答案是肯定的,但不是全部

    查询:

    说明 select * from IndexTest where ID

    如果你使用innodb,则使用表簇索引,它的表的主键,所以它使用primary进行查询

    第二个查询:

    从 IndexTest 中选择 CREATED_TIME,其中 CREATED_TIME > UNIX_TIMESTAMP(CURRENT_DATE())*1000;

    这个只是获取索引列,mysql不需要从表中获取数据而只是索引,所以你的解释结果是“使用索引”

    查询:

    从 IndexTest 中选择 count(distinct(PID)) where CREATED_TIME > UNIX_TIMESTAMP(CURRENT_DATE())*1000;

    看起来像这样

    从 IndexTest 中选择 PID,其中 CREATE_TIME>UNIX_TIMESTAMP(CURRENT_DATE())*1000 按 PID 分组

    mysql也可以使用索引从数据库中获取数据,但是mysql认为这个查询不需要使用索引来获取数据,因为where条件过滤器,mysql认为使用索引获取数据比使用索引更昂贵扫描所有表,你也可以使用force index

    与您上次查询的原因相同

    这个答案可以帮助你

    【讨论】:

      【解决方案5】:

      索引有助于加快对特定列和相关数据的搜索,而不是表数据。所以你必须包含索引列来加速select

      【讨论】:

      • 这绝不是正确的形状或形式。选择的列是数据。索引是完全不同的,如果查询优化器认为它会产生与您是否选择列无关的好处,它们将被使用。
      • 在覆盖索引的情况下,这在技术上是正确的,但在 MySQL 中,覆盖索引似乎非常初级 - 它们与常规索引相同,它们只是恰好索引你在你的每一列select 语句,在 MySql 中意味着它们包含这些列中数据的完整副本,并且实际表不是回答查询所必需的。 dev.mysql.com/doc/refman/5.5/en/…
      猜你喜欢
      • 2014-08-19
      • 2011-01-25
      • 2021-12-28
      • 2015-07-02
      • 2018-07-22
      • 1970-01-01
      • 2015-09-22
      • 2015-01-09
      • 2017-02-21
      相关资源
      最近更新 更多