由于某种原因,加入更新需要9到30个小时?

时间:2015-04-04 06:46:51

标签: mysql

我有两个表,我们称之为table_A和table_B。 Table_A有大约1000万行。 Table_B有3亿行。我在Table_B列X和Y上创建了索引。

更新会因为我拥有的行数而花费这么长时间,这是正常的吗?考虑到我有一个索引

,这对我来说似乎非常长

这是他们的样子

表A:

ID   BCODE 
1    A1 
2    B1  
3    C1  
4    D1  
5    F1 

表B:

X    Y    IDX  IDY
A1   D1  
D1   F1  
C1   B1  

Table_B有列' X'和' Y'具有在表_A&#39的列BCODE中找到的值。

我运行两个更新语句,需要9到30个小时才能完成。

 Update Table_B
join table_A a on table_B.X = a.BCODE
set
   table_B.IDX=a.Id ;

Update Table_B
join Table_A aa on table_B.Y = aa.BCODE
set
   table_B.IDY = aa.Id  ;

无论如何我可以加快速度吗?我应该补充一点,BCODE,X,Y列最长可达300个字符

以下是Explain的结果:

+----+-------------+-----------+------+---------------+-------------+---------+--------------+----------+-------------+
| id | select_type | table     | type | possible_keys | key         | key_len |  ref         | rows     | Extra       |
+----+-------------+-----------+------+---------------+-------------+---------+--------------+----------+-------------+
|  1 | SIMPLE      | a         | ALL  | BCODE         | NULL        | NULL    | NULL         | 10238784 | NULL        |
|  1 | SIMPLE      | table_B   | ref  | relateIndex   | relateIndex | 632     | test.a.BCODE |       15 | Using where |
+----+-------------+-----------+------+---------------+-------------+---------+------------+----------+-------------+
2 rows in set (0.00 sec)

2 个答案:

答案 0 :(得分:4)

创建covering index

create index table_a_bcode_id on table_A(bcode, id);

覆盖索引提供索引中的查找值,避免访问表 - 使得仅索引查询成为可能。

您的查询看起来不错,但请尝试将它们合并:

update Table_B
left join table_A a1 on a1.BCODE = table_B.X
left join table_A a2 on a2.BCODE = table_B.Y
set table_B.IDX = a1.Id
    table_B.IDY = a2.Id

这避免了必须两次更新行。

答案 1 :(得分:2)

从EXPLAIN输出看,Table_A.BCODE看起来没有BCODE的索引。如果你想进行JOIN,那么两个表都应该在JOIN字段上建立索引,否则由于查找的O(N)复杂性,非索引表会减慢速度。

除此之外,您已经提到两列都是长达300个字符的字符串。这些栏目的指数不是很有效。如果您可以找到一种方法来散列这些列中的值,然后通过散列值执行连接,则可以加快速度。

另一方面,对于较大的表,您应该检查索引是否适合内存。如果他们不这样做,那么MySQL将开始将您的索引交换到磁盘,这将极大地降低速度。

我们可以做一个估计:600(你的索引密钥长度)x 300M(行数)= 200 GB ......所以很可能这就是问题。

可能的解决方法:尝试对table_B进行分区(例如,通过PK),以便索引可以适合内存的每个部分(它可能意味着25个或更多分区,假设您的MySQL实例最多可以使用8 GB RAM)。