我有三个大表,A
(1000万行),A_C
(6000万行)和C
(6行)。它们通过bigint
字段和主要外键关系相关联。这些表具有n:m关系,这就是我添加A_C
表的原因。架构如下:
A.id = A_C.a_id
和
C.id = A_C.c_id
A
是此处的主要表格。我想显示A
的前100个条目以及C
到A_C
的所有相应行。目前查询需要很长时间。我的第一种方法是两个简单的连接。运行EXPLAIN ANALYZE
我发现,SQL在A
上执行顺序扫描。我认为这是因为它最后应用了限制而忽略了它。这表现得非常糟糕。有没有办法解决这个LIMIT
或我在这里缺少的另一种解决方案?当我在一个简单的选择查询上执行LIMIT
时,它在~2ms内执行得很好。
编辑:A.id
是主键并具有btree索引。 A_C
对整行以及A_C.a_id
和A_C.c_id
上的索引都有唯一约束。我还没有加入C
因为它已经很慢了。
快速查询:
SELECT A.id FROM A
SELECT A.id FROM A LIMIT 10
慢查询:
以下是查询计划的快速但执行速度慢,因为数据量非常大:
SELECT A.id FROM A JOIN A_C ON A.id = A_C.a_id
我尝试通过设置检索A
的行数限制来避免这种情况:
SELECT a.id FROM (SELECT A.id AS id FROM metrics.metrics LIMIT 10) a JOIN A_C ON (a.id = A_C.a_id)
EXPLAIN ANALYZE
的查询计划如下:
"Hash Join (cost=5.75..1305897.53 rows=44790854 width=8) (actual time=251969.648..251969.648 rows=0 loops=1)"
" Hash Cond: (a_c.a_id = a.id)"
" -> Seq Scan on a_c (cost=0.00..690017.54 rows=44790854 width=8) (actual time=0.472..126203.253 rows=44790000 loops=1)"
" -> Hash (cost=4.50..4.50 rows=100 width=8) (actual time=1.889..1.889 rows=100 loops=1)"
" Buckets: 1024 Batches: 1 Memory Usage: 12kB"
" -> Limit (cost=0.00..3.50 rows=100 width=8) (actual time=0.527..1.550 rows=100 loops=1)"
" -> Seq Scan on a (cost=0.00..261275.88 rows=7465088 width=8) (actual time=0.520..0.912 rows=100 loops=1)"
"Planning time: 16.350 ms"
"Execution time: 251969.693 ms"
答案 0 :(得分:1)
我会为a
:
select . . .
from (select a.*
from a
order by a.id
fetch first 100 rows only -- or limit 100
) a join
a_c ac
on ac.a_id = a.id join
c
on ac.c_id = c.id;
即使c
非常小,但如果您还没有主键,我会鼓励c(id)
使用主键。
这假设“前100行”是指主键的排序。