【问题标题】:SQL query incredibly slow when using simple NOT IN (SUBQUERY)使用简单的 NOT IN (SUBQUERY) 时 SQL 查询速度非常慢
【发布时间】:2017-11-01 00:51:57
【问题描述】:

我一直在尝试从两个表中获取反转的结果集,以下是一些技术细节:

初始表

CREATE TABLE `initial_table` (`id` varchar(255) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`))

另一张桌子

CREATE TABLE `another_table` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`row_id` varchar(255) NOT NULL DEFAULT '',PRIMARY KEY (`id`),KEY `row_id` (`row_id`))

解释尝试的语句

id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | PRIMARY | initial_table | index | NULL | PRIMARY | 767 | NULL | 2965400 | Using where; | Using index
2 | DEPENDENT SUBQUERY | another_table | index | NULL | row_id | 257 | NULL | 770452 | Using where; | Using index

在 another_table 中是 initial_table 的子集。初始表大约有 3,000,000 行,another_table 是 600,000 行。我想从 another_table 中得到结果的倒数,基本上是 initial_table 中不存在于 another_table 中的 2,400,000 行。

我尝试了以下查询:

INSERT INTO results_table SELECT a.id FROM initial_table AS a LEFT OUTER JOIN another_table AS z ON a.id = z.row_id WHERE z.row_id IS NULL
INSERT INTO results_table SELECT a.id FROM initial_table as a WHERE NOT IN (SELECT z.row_id FROM another_table AS z)
INSERT INTO results_table SELECT a.id FROM initial_table AS a WHERE NOT EXISTS (SELECT z.row_id FROM another_table AS z WHERE a.id = z.row_id)
INSERT INTO results_table SELECT a.id FROM initial_table AS a WHERE NOT EXISTS (SELECT 1 FROM another_table AS z WHERE a.id = z.row_id)

上述所有方法在 4 小时的执行中(最多)产生了 34,000 行,AWS 表示它的选择速度约为 1.89 SELECTs/秒

我可以在这里执行某种形式的优化吗?遗憾的是,initial_table 主键是一个包含 UUID 的 varchar,而不是基于整数的主键,但至少所有相关列都被索引了。不知道为什么它这么慢,因为至少在理论上,WHERE NOT EXISTS(第三个)查询不应该进行表扫描,而只是基于索引的查找:/

【问题讨论】:

  • 澄清一下 - 正在运行的 RDS 实例相当不错 - 4CPU/16GB RAM,这不是硬件瓶颈 - CPU 最高约为 30-40%。
  • 一个CPU瓶颈,当然,在0到100的尺度上……4个vCPU,单个查询只能消耗25%。您还需要解释两个表 (767/257) 之间 key_len 的差异,这意味着 varchar(255) 和 int(11) 的两种不同排序规则在任何地方都看不到。
  • 这很有意义 - 我不知道 SQL 每次查询都绑定到一个 vCPU。我不是 100% 确定你所说的两个 key_lens 的差异是什么意思,尽管我在 CREATE 中确实有一个错误,因为 row_id 应该是 varchar(255) 而不是 int(11)。我相信在 initial_table 中可能有一个坏/虚拟键比任何检索并放入 another_table 的键长得多,这可以解释 key_len 的区别吗?
  • 767 是存储 255 个 utf8 字符可能需要的最大字节数 - (255 × 3) + 2 更多存储长度(在实际行中)......所以它可能是正确的但与另一个表不一致,可能需要某种隐式转换或强制转换。

标签: mysql sql amazon-rds


【解决方案1】:

我会去:

INSERT INTO results_table (id)
    SELECT a.id
    FROM initial_table a
    WHERE NOT EXISTS (SELECT 1 FROM another_table z WHERE a.id = z.row_id);

对于此查询,您需要在another_table(row_id) 上建立索引。

【讨论】:

  • 我没有包含在我最初的帖子中,但我已经尝试过 - 它具有相同的结果。我用这个查询再次测试,我得到大约 1.9 次插入/秒,现在已经修改了。
  • @TomPrentice 。 . .你有索引吗?
  • 我确实设置了索引 - 如我提供的 CREATE 语句所示:)
  • @TomPrentice 。 . .您的表定义与查询中使用的列不匹配。
  • 很抱歉 - 这也已修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-07
相关资源
最近更新 更多