使用复合索引优化更新查询

时间:2016-05-15 00:39:48

标签: mysql indexing

我测试了两个大的(每个约5密耳的记录)之间的更新,每次更新需要10秒左右。所以,我第一次做了解释测试选择:

SELECT
    T1.Z, T2.Z
FROM
    TableB T1
INNER JOIN TableL T2
    on T1.Name=T2.Name 
   and T1.C=T2.C
   and T1.S=T2.S
   and T1.Number>=T2.MinNumber
   and T1.Number<=T2.MaxNumber

Explain将以下内容作为可能的键返回:

  • 名称
  • C
  • 取值

并选择C作为关键。

有人告诉我,我最好的选择是制作一个复合键,按照选择的顺序,我做了

Alter Table TableB Add Index Compound (Name,C,S,Number)

又做了一个解释,希望它会选择我的化合物,但现在即使它显示复合指数作为可能的关键,它仍然选择指数C.

我读到我可以强制使用我想要的索引:

SELECT
    T1.Z, T2.Z
FROM TableB T1 Force Index(Compound)
INNER JOIN TableL T2
    on T1.Name=T2.Name 
   and T1.C=T2.C
   and T1.S=T2.S
   and T1.Number>=T2.MinNumber
   and T1.Number<=T2.MaxNumber

但我不确定覆盖MySql的选择是否有任何意义,并且如果它没有帮助更新将花费将近两年的时间,那么测试似乎并不是一件好事。

我有什么步骤吗?我是否需要删除其他键以便选择我的复合键,如果是这样,我怎么知道它是否会产生影响(假设Mysql看到它并拒绝它)?

解释T1上的输出: (注意:我还没有添加复合索引,因为表格很大,可能是浪费时间,直到我想出来。我之前添加了它在一个高度截断的表格版本,但这将无助于解释) 表1

  • select_type:simple
  • type:ref
  • possible_keys:
  • 数字,C,S,名称
  • key:名称
  • key_len:303
  • ref:func
  • 行:4
  • 额外:使用where

解释表2

  • select_type:SIMPLE
  • 类型:ALL
  • possible_Keys:MinNumber,MaxNumber
  • 键:
  • key_length:
  • REF:
  • 行:5,447,100
  • 额外:

基数 (仅显示与此相关的索引,因为还有其他几个):

  • 小学:5139680

  • 姓名:1284920

  • 编号:57749

  • C:7002

  • S:21

2 个答案:

答案 0 :(得分:3)

因此,基于一些出色的评论/输入,我想出了一个解决方案。来自Paul Spiegel的一个flashbulb输入是不建议尝试使用几个VarChar字段连接两个5 + mil表。

所以我做的是创建一个带ID和UnqiueRecord字段的UniqueTable。

然后我将UniqueRecord设为唯一索引。

我从TableA和TableB插入到该表中:

Insert IGNORE into `Unique` (UniqueRecord) 
Select Concat(Name,C,S) from Table1 Group by Name,C,S;
Insert IGNORE into `Unique` (UniqueRecord) 
Select Concat(Name,C,S) from Table2 Group by Name,C,S

这给了我两张表内和表之间的独特记录。

然后我在表1和表2中添加了一个UniqeRecord_ID字段。

然后我在每个表和UniqueRecord之间进行了连接,以便为每个表写入UniqueRecord ID:

Update Table1 as T1
Inner Join Unique as T2
On Concat(T1.Name,T1.S,T1.C) = T2.UniqueRecord
Set T1.UniqueRecord_ID=T2.ID

最后,我在UniqueRecord_ID上为每个表添加了一个键。

我的解释显示它只使用了来自T2的那个键,但是对于选择之前的每个记录需要10秒(我在1,10,100上测试并且在那里停止,因为我没有必要的578天来测试整个表:|)整个选择,返回接近500万条记录需要72秒。

答案 1 :(得分:0)

请注意,必须完全扫描第一个表格(无论哪个表格)。所以,我们能做的最好的就是在第二个表上有一个好的索引。

T1的最佳指数(如前所述)为(Name,C,S,Number)。对于T2,它是(Name,C,S,MinNumber,MaxNumber),这是更大的。

优化器似乎想从T1开始;也许它稍微小一些。通过将INNER JOIN更改为STRAIGHT_JOIN并交换订单,强制它从T2开始:

SELECT
    T1.Z, T2.Z
FROM          TableL T2   -- note
STRAIGHT_JOIN TableB T1   -- note
    on T1.Name=T2.Name 
   and T1.C=T2.C
   and T1.S=T2.S
   and T1.Number>=T2.MinNumber
   and T1.Number<=T2.MaxNumber

然后,让我们再做一次优化:如果Z不是太大&#39;,请将其包含在索引末尾,以便它变为a&#34;覆盖指数&#34;:

INDEX(Name,C,S,Number,Z)

Name, C, S可以按任何顺序排列,但Number, Z必须按顺序排列,最后才是。)如果您目前有INDEX(Name)DROP就是多余的。

然后EXPLAIN会说你正在对T2进行全表扫描,加上一个&#34;使用索引&#34;在T1上。

请提供SHOW CREATE TABLE;可能会有更多的优化。