【发布时间】: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