如果这应该发布在DBA.stackexchange.com上,请告诉我......
我有以下查询:
SELECT DISTINCT "court_cases".*
FROM "court_cases"
LEFT OUTER JOIN service_of_processes
ON service_of_processes.court_case_id = court_cases.id
LEFT OUTER JOIN jobs
ON jobs.service_of_process_id = service_of_processes.id
WHERE
(jobs.account_id = 250093
OR court_cases.account_id = 250093)
ORDER BY
court_cases.court_date DESC NULLS LAST,
court_cases.id DESC
LIMIT 30
OFFSET 0;
但是运行需要2-4秒,而在Web应用程序中,单个查询是不可接受的。
我按照建议on the PostgreSQL wiki对查询运行EXPLAIN (ANALYZE, BUFFERS)
,并将结果放在此处:http://explain.depesz.com/s/Yn6
查询中涉及的那些表的表定义(包括外键关系的索引):
http://sqlfiddle.com/#!15/114c6
使用索引是否有问题,因为WHERE
子句正在从两个不同的表中查询?我可以使用哪种索引或更改来使其运行更快?
这些是当前相关表格的大小:
PSQL=# select count(*) from service_of_processes;
count
--------
103787
(1 row)
PSQL=# select count(*) from jobs;
count
--------
108995
(1 row)
PSQL=# select count(*) from court_cases;
count
-------
84410
(1 row)
编辑:我正在使用Postgresql 9.3.1,如果这很重要。
答案 0 :(得分:3)
or
子句可以使查询优化变得困难。一种想法是将查询的两个部分分成两个独立的子查询。这实际上简化了其中一个(court_cases.account_id
上的那个)。
试试这个版本:
(SELECT cc.*
FROM "court_cases" cc
WHERE cc.account_id = 250093
ORDER BY cc.court_date DESC NULLS LAST,
cc.id DESC
LIMIT 30
) UNION ALL
(SELECT cc.*
FROM "court_cases" cc LEFT OUTER JOIN
service_of_processes sop
ON sop.court_case_id = cc.id LEFT OUTER JOIN
jobs j
ON j.service_of_process_id = sop.id
WHERE (j.account_id = 250093 AND cc.account_id <> 250093)
ORDER BY cc.court_date DESC NULLS LAST, id DESC
LIMIT 30
)
ORDER BY court_date DESC NULLS LAST,
id DESC
LIMIT 30 OFFSET 0;
并添加以下索引:
create index court_cases_accountid_courtdate_id on court_cases(account_id, court_date, id);
create index jobs_accountid_sop on jobs(account_id, service_of_process_id);
请注意,第二个查询使用and cc.count_id <> 250093
,这可以防止重复记录。这样就不需要distinct
或union
(没有union all
)。
答案 1 :(得分:0)
我将尝试按以下方式修改查询:
SELECT DISTINCT "court_cases".*
FROM "court_cases"
LEFT OUTER JOIN service_of_processes
ON service_of_processes.court_case_id = court_cases.id
LEFT OUTER JOIN jobs
ON jobs.service_of_process_id = service_of_processes.id and jobs.account_id = 250093
WHERE
(court_cases.account_id = 250093)
ORDER BY
court_cases.court_date DESC NULLS LAST,
court_cases.id DESC
LIMIT 30
OFFSET 0;
我认为问题在于查询规划器优化器没有正确分解where过滤器,这是一个非常奇怪的性能错误