【问题标题】:How does Index Hint and Query Execution Plan Work?索引提示和查询执行计划如何工作?
【发布时间】:2012-01-01 11:17:46
【问题描述】:

我正在运行一系列测试以确定忽略索引如何影响我的查询速度。以下是第一个测试系列的查询字符串:

SELECT P.pid, P.name, P.cty, P.fla, P.pos, P.lvl, P.akP * E.usD AS 'ask'
 FROM Pig P
 IGNORE INDEX FOR JOIN (id_fla) // index is on fla (MEDIUMINT) column
 INNER JOIN Eel E ON E.cur = P.cur
 WHERE P.status IN ('a', 'l') AND P.fla >107 AND P.cDate >CURDATE() AND P.pos <45
 HAVING ask BETWEEN '50' AND '500'
 ORDER BY fla DESC
 LIMIT 100;

在第二个测试系列中,IGNORE INDEX FORJOIN 被替换为 IGNORE INDEX FORORDER BY。而在第三个测试系列中,IGNORE INDEX FOR ORDER BY 被替换为 IGNORE INDEX FOR GROUP BY

下面是测试结果和对应的查询执行计划。

测试 1(连接时忽略索引):

Query Number (n): 1    2    3    4    5    6    7    8    9    10
Query Times (s):  90.6 0.13 27.2 21.4 0.11 0.10 29.8 27.8 0.17 6.56
Rows Examined (k):26   26   36   43   37   37   58   85   66   98

测试 2(忽略 ORDER BY 的索引):

Query Number (n): 1    2    3    4    5    6    7    8    9    10
Query Times (s):  90.7 0.14 26.5 21.2 0.10 0.11 35.0 28.5 0.17 6.64
Rows Examined (k):26   26   36   43   37   37   58   85   66   98

测试 3(忽略 GROUP BY 的索引):

Query Number (n): 1    2    3    4    5    6    7    8    9    10
Query Times (s):  263  10.1 10.1 9.95 9.94 10.1 10.0 9.95 9.96 10.1
Rows Examined (M):4.18 4.18 4.18 4.18 4.18 4.18 4.18 4.18 4.18 4.18
  • 注 1:s - 秒,k - 千,M - 百万
  • 注 2:pos 是唯一在查询之间变化的 WHERE 条件 1 到 10。WHERE 条件在 每个查询编号进行三个测试。

测试 1(连接时忽略索引):

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: P
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5000014
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: E
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: BS.P.cur
         rows: 1
        Extra: 

测试 2(IGNORE INDEX FOR ORDER BY)和测试 3(IGNORE INDEX FOR GROUP BY):

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: P
         type: range
possible_keys: id_flA
          key: id_flA
      key_len: 3
          ref: NULL
         rows: 4223660
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: E
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: BS.P.cur
         rows: 1
        Extra: 

尽管测试 2 和测试 3 的查询执行计划与测试 1 相同且不同,但实际查询速度和检查的行似乎将测试 1 和测试 2 组合在一起。所以我有两个问题需要问:

  1. 索引提示在这种情况下如何工作?
  2. 似乎在测试 3 上执行了表扫描,但索引显示为 使用。 MySQL 是否遵循查询执行计划 EXPLAIN SELECT 声明?

【问题讨论】:

  • 索引提示可以帮助优化器在应用多个索引时最适合您的查询。也就是说,使用您提供的缩写查询,您能否提供完整的查询并限定“where”子句字段与哪个表相关联。此信息可能会更好地提供解决方案,帮助您了解哪些索引可能最适合性能...此外,您的查询将执行的一些主要目的(条件)是什么。
  • @DRapp:我在fla 列上有一个简单的索引,在pid 上有一个主键。 where 子句都与表 PIG 相关联。我已经修改了上面的查询。可以看看吗?

标签: mysql optimization


【解决方案1】:
   WHERE 
          P.status IN ('a', 'l') 
      AND P.fla > 107 
      AND P.cDate > CURDATE() 
      AND P.pos < 45
   HAVING 
      ask BETWEEN '50' AND '500'

您的查询本身看起来不错(只是澄清了您帖子中的格式)。但是,如果您拥有的唯一索引是在 fla 上,那就有问题了。索引应基于您的查询条件所基于的...尝试更多地关注常见的查询条件,这些条件应该派生最小粒度以帮助优化..我不知道哪个会更好...根据状态,或基于 cDate 的条目,然后是您在 fla 和 pos 列上的位置。例如,如果您有 400 万个条目,其中 500k 是状态“a”,400k 是状态“l”,但只有 20k 且 cDate > curdate(),那将是您索引的起点...索引在 CDate 上...然后添加下一级粒度。如果您有 15 个不同的状态代码,那么该 cDate 段中每个状态有多少个?但是你比 S/O 的任何人都更了解你的数据,但我会提出这个索引的建议。

在 (status, cdate, fla, pos ) 上建立索引并尝试,然后在 (cdate, status, fla, pos ) 上建立另一个索引,看看哪个有助于您的表现。 107 上存在多少个“fla”值?如果它的数量很少,那么可能会将 THAT 作为你的第一个索引限定符,但我怀疑它,因为你试图不使用那个。

祝你好运,希望这能帮助你更多地思考你的数据。

【讨论】:

  • 我尝试过使用复合索引,但由于flapos是可以覆盖所有行或不覆盖所有行的值,cDatastatus覆盖最多行。
猜你喜欢
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多