【发布时间】:2016-10-19 10:00:17
【问题描述】:
我有两张桌子
table1:
column1: varchar(20) column2: varchar(20) column3: varchar(20)
table2:
column1: varchar(20) column2: varchar(20) column3: varchar(20) <- empty
column1 和column2 在table1 中都有单独的全文索引
两个表都包含 2000 万行
我需要通过将table2 中的table2 到column1 和column2 中的column2 匹配来填充table2 中的column3,然后从@ 中获取column3 中的值987654332@ 并放入column3 的table2。 column1 & column2 可能不完全匹配,所以我使用的查询是:
UPDATE table1, table2
SET table2.column3 = table1.column3
WHERE table2.column1 LIKE table1.'%column1%' AND
table2.column2 LIKE table1.'%column2%';
此查询永远不会完成。我让它运行了 2 周,但仍然没有产生任何结果。它 100% 使用了一个 CPU 内核,SSD IO 很少,显然需要以某种方式进行优化。
我愿意接受有关查询优化、索引优化甚至 DBMS 优化(甚至是迁移,如果有帮助的话)的任何建议,因为我将来需要更频繁地执行此类查询。
EDIT1
有很多优化指南,请使用谷歌。您可以增加配置中的线程(InnoDB)。对于更新本身,我建议先创建一个 temp_table,然后复制到 db2
我知道这一点,但无法通过这些指南完全解决我的情况。我也知道这个问题的所有可能组合排列的问题(巨大的数据库、性能、瓶颈、查询设计)无处不在,也在 stackoverflow 上。但是,直到今天,我还想不出解决这种特定问题组合的最佳方法是什么,并希望在这里获得帮助。话虽如此: - 更多线程需要分片或分区才能使用多个 CPU 内核,如果我可以通过其他方式解决问题,我想避免这种情况 - 你建议如何在这里创建这样的临时表?
如果不使用通配符,为什么还要使用 like 运算符?将它们替换为 =。另外,您是否在每个表的 where 条件中的 3 列上有多列索引?请分享解释的输出,以及 2 个表中的任何现有索引。
- 我在示例中省略了这些字符,但希望在基本查询工作后使用它们,很抱歉造成混淆。不过,我不完全确定如何将这些通配符放入列比较中。
- 我有两个单独的索引,我应该创建一个 2 列索引吗? (where 条件中只有 2 列)
- 您更喜欢我现在拥有的结构的解释,还是更喜欢具有 2 列索引的结构的解释?
我猜你说的是数据库,但你说的是表,对吧?
没错,很抱歉造成混乱。
您编写的查询将执行 20m x 20m 的查找(对于表 1 中的每一行,查找表 2 中的所有行)。如果你有一个 SSD 或一个好的 CPU,你不能写任何东西并期望它工作。如果您已经到了这一点,那么是时候在开始编写 SQL 之前进行思考了。你需要做什么,你有什么工具可以使用,中间有什么你不知道的——这些是你每次发出 4000 亿查询查询之前需要回答的问题。
这就是我所面临的情况。老实说,我不希望它像现在这样工作,所以我正在寻找可能使这成为可解决方案的指针。基本的“更新这个,匹配的地方”查询显然不适用于这里。所以我试图找出一种更高级的解决方案。非常欢迎任何批评,所以感谢您的意见。您建议如何在这里进行?
EDIT2
给我们一些样本值和不精确的比较。
table1:
+---------+---------+-------------+---------+---------+---------+
| column1 | column2 | column3 | column4 | column5 | columnN |
+---------+---------+-------------+---------+---------+---------+
| John | Doe_ | employee001 | xyz | 12345 | ... |
| Jim | Doe | employee002 | abc | 67890 | ... |
+---------+---------+-------------+---------+---------+---------+
table2:
+---------+---------+---------+
| column1 | column2 | column3 |
+---------+---------+---------+
| John | Doe | |
| Jim | Doe | |
+---------+---------+---------+
这里,如果 LIKE 查询匹配“Doe_”的“Doe”,它将填充表 2 的两行。但是通过写下来,我刚刚意识到 LIKE 查询在这里不是选项,因为变体不会限制为表 1 中 column2 的后缀,而是需要各种可能的喜欢(前导和尾随变体)表)。这反过来又会增加所需匹配的数量。 所以让我们忘记 LIKE,只关注精确匹配。
FULLTEXT 和 LIKE 没有任何关系。
“可能不完全匹配”——您需要对这种非限制进行更多限制。否则,任何查询尝试都将持续数周时间。
t2.c1 LIKE CONCAT('%', t1.c1, '%') 需要检查 t1 的每一行与 t2 的每一行;那是 400 万亿次测试。没有任何硬件可以在合理的时间内做到这一点。
FULLTEXT 适用于“单词”。如果您的 c1 和 c2 是字符串,那么使用 FULLTEXT 是有希望的。 FULLTEXT 比 LIKE 快得多,因为它具有基于单词的索引结构。
然而,即使是 FULLTEXT 也远不及 t2.c1 = t1.c1 的速度。尽管如此,这仍需要一个复合 INDEX(c1, c2) 然后它将是一个表的全表扫描(20M 行),再加上通过 BTree 索引对另一个表进行的 20M 探测。这就像 40M 操作——比 LIKE 的 400T 好很多。
为了继续,请仔细考虑您对“可能不完全匹配”的定义,并提出您可以接受的最佳情况。
好的,既然我决定放弃 LIKE 要求,那么您究竟打算使用什么作为索引? 我是这样看你的帖子的:
ALTER TABLE `table1` ADD FULLTEXT INDEX `indexname1` (`column1`, `column2`);
ALTER TABLE `table2` ADD FULLTEXT INDEX `indexname2` (`column1`, `column2`);
UPDATE `table1`, `table2`
SET `table2`.`column3` = `table1`.`column3 `
WHERE CONCAT(`table1`.`column1`, `table1`.`column2`) = CONCAT(`table2`.`column1`, `table2`.`column2`);
这对吗?
不过有两个后续问题: 1)您认为更新是否与创建新表一样快,更快或更慢,即:
CREATE TABLE `merged` AS
SELECT `table1`.`column1`, `table1`.`column2`, `table1`.`column3`
FROM `table1`, `table2`
WHERE CONCAT(`table1`.`column1`, `table1`.`column2`) = CONCAT(`table2`.`column1`, `table2`.`column2`);
2) indizes 和/或匹配是否区分大小写?如果是,是否可以调整查询而无需将 column1 和 column2 更改为全部大写(或全部小写)?
【问题讨论】:
-
优化指南很多,请自行google。您可以增加配置中的线程(InnoDB)。对于更新本身,我建议首先创建一个 temp_table,然后复制到 db2
-
如果不使用通配符,为什么还要使用like运算符?将它们替换为
=。另外,您是否在每个表的 where 条件中的 3 列上有多列索引?请分享解释的输出,以及 2 个表中的任何现有索引。 -
我猜你说的是数据库,但你说的是表,对吧?
-
您编写的查询将执行 20m x 20m 的查找(对于表 1 中的每一行,查找表 2 中的所有行)。如果你有一个 SSD 或一个好的 CPU,你不能写任何东西并期望它工作。如果您已经到了这一点,那么是时候在开始编写 SQL 之前进行思考了。您需要做什么,您可以使用哪些工具以及您不知道的中间部分是什么——这些是您每次发布前都需要回答的问题4000 亿次查找查询。
-
给我们一些样本值和非精确比较。
标签: mysql join optimization