加入复合键时MySQL很慢

时间:2016-05-24 17:11:10

标签: mysql

我们有两张桌子:

create table A (
  id int,
  a int,
  b int,
  c varchar(255),
  unique key K1 (a,c),
  key K2 (b,c),
  key K3 (a,b,c)
);
create table B (
  id int,
  b int,
  c varchar(255),
  x varchar(255),
  unique key K (b,c)
);

运行以下查询:

SELECT B.x 
FROM B 
INNER JOIN A 
   ON A.b = B.b 
  AND A.c = B.c
WHERE A.a IN (...a values...);

a values来自客户端语言(我们的案例:Ruby),以及大约10-100,000个项目。

解释是这样的。

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: A
         type: range
          key: K
      key_len: 4
          ref: NULL
         rows: 100
        Extra: Using where; Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: app_devices
         type: ref
          key: K
      key_len: 4
          ref: A.b
         rows: 213
        Extra: Using index condition
2 rows in set (0.00 sec)

当A和B很小时,此查询很有效,但当表大小超过大约2000万行时,它会变慢。 我怀疑复合键在加入时效果不佳。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

C是VARCHAR(255)的索引,它在长度方面非常大,并且还包括所有不包括数字的字符。如果VARCHAR的长度实际上总是255,那么你应该将它设置为CHAR,看看那个展览会的时间。

但是,如果你有2000万行,这意味着你的自动增量ID只有8的长度,并且只包含数字,这更适合你的连接。 像这样把ID放到桌子上;

 create table A (
  id int,
  a int,
  b int,
  c varchar(255),
  b_id int, //additional field
  unique key K1 (a,c),
  key K2 (b,c),
  key K3 (a,b,c)
);
create table B (
  id int,
  b int,
  c varchar(255),
  x varchar(255),
  unique key K (b,c)
);

然后运行一次:

UPDATE a    
INNER JOIN B 
ON A.b = B.b 
AND A.c = B.c
SET a.b_id = b.id

然后您的查询变为:

SELECT B.x 
FROM B 
INNER JOIN A 
ON A.b_id = b.id
WHERE A.a IN (...a values...);

那应该在合理的时间内运行

编辑:

你的varchar(255)的长度总是255,还是可以短得多?你可以缩短它。

如果您在没有锁定的情况下复制包含所有记录的表,并在副本上执行添加自动增量更新,并在短暂的停机时间内(如果可能)将其重命名为原始数据库。

您可以使用以下问题来确定这是否适合您。 :

Surrogate vs. natural/business keys