我有这样的模型
具有以下表格大小:
+------------------+-------------+
| Table | Records |
+------------------+-------------+
| JOB | 8k |
| DOCUMENT | 150k |
| TRANSLATION_UNIT | 14,5m |
| TRANSLATION | 18,3m |
+------------------+-------------+
现在进行以下查询
select translation.id
from "TRANSLATION" translation
inner join "TRANSLATION_UNIT" unit
on translation.fk_id_translation_unit = unit.id
inner join "DOCUMENT" document
on unit.fk_id_document = document.id
where document.fk_id_job = 11698
order by translation.id asc
limit 50 offset 0
需要 90秒才能完成。当我删除 ORDER BY 和 LIMIT 子句时,它需要 19.5秒。在执行查询之前,已在所有表上运行 ANALYZE 。
对于此特定查询,这些是满足条件的记录数:
+------------------+-------------+
| Table | Records |
+------------------+-------------+
| JOB | 1 |
| DOCUMENT | 1200 |
| TRANSLATION_UNIT | 210,000 |
| TRANSLATION | 210,000 |
+------------------+-------------+
查询计划:
没有 ORDER BY 和 LIMIT 的修改的查询计划是here。
数据库参数:
PostgreSQL 9.2
shared_buffers = 2048MB
effective_cache_size = 4096MB
work_mem = 32MB
Total memory: 32GB
CPU: Intel Xeon X3470 @ 2.93 GHz, 8MB cache
有人能看到这个查询有什么问题吗?
更新:Query plan用于没有 ORDER BY 的相同查询(但仍然使用 LIMIT 子句)。
答案 0 :(得分:2)
评论时间太长了。删除order by
子句时,您正在比较苹果和橙子。如果没有order by
,查询的处理部分只需要提供50行。
使用order by
,所有行都需要在排序之前生成,并选择前几行。如果删除order by
和 limit
子句,查询需要多长时间?
translation.id
是主键的事实并没有什么区别,因为处理需要经过多次连接(过滤结果)。
编辑:
我想知道如何使用CTE首先创建表,然后另一个用于排序和获取结果:
with CTE as (
select translation.id
from "TRANSLATION" translation
inner join "TRANSLATION_UNIT" unit
on translation.fk_id_translation_unit = unit.id
inner join "DOCUMENT" document
on unit.fk_id_document = document.id
where document.fk_id_job = 11698
)
select *
from CTE
order by translation.id asc
limit 50 offset 0;
答案 1 :(得分:1)
翻译时是否有复合索引(fk_id_translation_unit,id)?在我看来,这将有助于避免通过表格访问translation.id的需要。
答案 2 :(得分:1)
如果有人遇到同样的问题。它发生在我身上,我通过将索引更改为有序索引来解决它。索引通过列 ID(PK 列)和顺序方向进行扩展。
像这样:
create index index_name on SCHEMA.TABLE (id asc, (sent_time IS NULL), some_id_ref, type);