MySQL:连接小到大表的性能不佳
Posted
技术标签:
【中文标题】MySQL:连接小到大表的性能不佳【英文标题】:MySQL: poor performance joining small to large table 【发布时间】:2017-02-27 16:36:58 【问题描述】:我有以下表格:
CREATE TABLE smalltable (
smalltable_id VARCHAR(64) NOT NULL,
bigtable_id VARCHAR(64),
...
PRIMARY KEY (smalltable_id)
) ENGINE=InnoDB;
CREATE TABLE bigtable (
bigtable_id VARCHAR(64) NOT NULL,
count BIGINT,
PRIMARY KEY (bigtable_id)
) ENGINE=InnoDB;
smalltable
大约有 8000 行,bigtable
大约有 4000 万行。我想从smalltable
中检索这些行,其中smalltable.bigtable_id
存在于bigtable
中。以下查询花费了将近 10 个小时来完成:
SELECT * FROM smalltable
INNER JOIN bigtable
ON smalltable.bigtable_id = bigtable.bigtable_id;
这是EXPLAIN
的输出:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: smalltable
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 8610
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: bigtable
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 38818260
filtered: 100.00
Extra: Using where; Using join buffer (Block Nested Loop)
我不是解释这一点的专家,但看起来 mysql 正在对两个表进行顺序扫描。如果我编写一个小 Python 脚本,它遍历 smalltable
中的所有行并在 bigtable
上为 smalltable
中的每一行执行 SELECT
查询,整个事情在 25 秒内完成。我希望通过单个 SQL 查询获得同样的性能。
【问题讨论】:
在 smalltable (bigtable_id) 上添加索引 谢谢。这确实大大加快了速度。现在查询需要 1 分 30 秒。不过,仍然比手动迭代 smalltable 并触发对 bigtable 的选择查询要慢。此外,最好有一个不需要更改小表的解决方案。在实际用例中,smalltable 中的数据是另一个大表的子集,我没有那个表的写权限。 索引是它所在的位置。另一种方法是做你已经在做的事情。 检查两个表中bigtable_id
的COLLATION
-- 必须相同。
join_buffer_size
的设置是什么?什么版本的 MySQL?
【参考方案1】:
查看优化器路径,哪个表是主源,好像很慢,用bigtable作为主源。试试这个:
SELECT STRAIGHT_JOIN * FROM smalltable
INNER JOIN bigtable
ON smalltable.bigtable_id = bigtable.bigtable_id;
使用 STRAIGHT_JOIN 将告诉 mysql 遵循查询中表的顺序。
【讨论】:
【参考方案2】:如果您只需要来自smalltable
的信息(这是您的描述所暗示的),
SELECT *
FROM smalltable AS s
WHERE EXISTS (
SELECT *
FROM bigtable
WHERE bigtable_id = s.bigtable_id );
【讨论】:
以上是关于MySQL:连接小到大表的性能不佳的主要内容,如果未能解决你的问题,请参考以下文章