ndn*_*kov 19 sql postgresql performance set-operations relational-division
我有以下表格:
work_units - 自我解释workers - 自我解释skills - 如果您想要工作,每个工作单位都需要一些技能.每个工人都精通各种技能.work_units_skills - 加入表workers_skills - 加入表工作人员可以请求下一个适当的免费最高优先级(无论这意味着)分配给她的工作单元.
目前我有:
SELECT work_units.*
FROM work_units
-- some joins
WHERE NOT EXISTS (
SELECT skill_id
FROM work_units_skills
WHERE work_unit_id = work_units.id
EXCEPT
SELECT skill_id
FROM workers_skills
WHERE worker_id = 1 -- the worker id that made the request
)
-- AND a bunch of other conditions
-- ORDER BY something complex
LIMIT 1
FOR UPDATE SKIP LOCKED;
Run Code Online (Sandbox Code Playgroud)
这种情况使查询慢了8-10倍.
是否有更好的方式来表达work_units技能应该是技能的一部分workers或改善当前查询的东西?
更多背景:
skills表是相当小的.work_units并workers往往有极少数的相关技能.work_units_skills有索引work_unit_id.workers_skills移到CTE中.这略有改善(10-15%),但仍然太慢.一个简单的加速将是使用EXCEPT ALL而不是EXCEPT.后者删除重复项,这在这里是不必要的,可能很慢.
可能更快的替代方案是使用另一个NOT EXISTS而不是EXCEPT:
...
WHERE NOT EXISTS (
SELECT skill_id
FROM work_units_skills wus
WHERE work_unit_id = work_units.id
AND NOT EXISTS (
SELECT skill_id
FROM workers_skills ws
WHERE worker_id = 1 -- the worker id that made the request
AND ws.skill_id = wus.skill_id
)
)
Run Code Online (Sandbox Code Playgroud)
演示
http://rextester.com/AGEIS52439 - LIMIT删除后进行测试
(见下面的更新)
此查询work_unit使用简单的LEFT JOIN 找到一个好处,以在请求工作者具有的较短技能表中找到缺少的技能.诀窍是,每当有一个缺失的技能,也将在加入一个NULL值,这个值转换为1与work_unit被留下的所有的人去除0值即具有max的0.
作为经典SQL,这将是引擎优化的最有针对性的查询:
SELECT work_unit_id
FROM
work_units_skills s
LEFT JOIN
(SELECT skill_id FROM workers_skills WHERE worker_id = 1) t
ON (s.skill_id=t.skill_id)
GROUP BY work_unit_id
HAVING max(CASE WHEN t.skill_id IS NULL THEN 1 ELSE 0 END)=0
-- AND a bunch of other conditions
-- ORDER BY something complex
LIMIT 1
FOR UPDATE SKIP LOCKED;
Run Code Online (Sandbox Code Playgroud)
UPDATE
为了work_units没有技能,我们将work_units表格放入JOIN:
SELECT r.id AS work_unit_id
FROM
work_units r
LEFT JOIN
work_units_skills s ON (r.id=s.work_unit_id)
LEFT JOIN
(SELECT skill_id FROM workers_skills WHERE worker_id = 1) t
ON (s.skill_id=t.skill_id)
GROUP BY r.id
HAVING bool_or(s.skill_id IS NULL) OR bool_and(t.skill_id IS NOT NULL)
-- AND a bunch of other conditions
-- ORDER BY something complex
LIMIT 1
FOR UPDATE SKIP LOCKED;
Run Code Online (Sandbox Code Playgroud)
根据目前的信息,我只能凭直觉回答。尝试删除 EXCEPT 语句,看看它是否会变得更快。如果是,您可以再次添加该部分,但使用 WHERE 条件。根据我的经验,集合运算符(减/除、并、交)是性能杀手。
| 归档时间: |
|
| 查看次数: |
864 次 |
| 最近记录: |