大桌子
record (
id number primary key,
city_id number not null,
organization_id number not null,
department_id number not null, -- extra context, can be 0
renew_date date not null -- frequently updated
)
使用两种查询:
1。
WITH cte (city_id, organization_id, -- etc...) AS (
-- table join routine...
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = 0
WHERE -- some condition on renew_date... whatever
2。
WITH cte (city_id, organization_id, department_id, -- etc...) AS (
-- same
)
SELECT r.*
FROM record r
INNER JOIN cte t ON r.city_id = t.city_id AND r.organization_id = t.organization_id AND r.department_id = t.department_id
WHERE -- some condition on renew_date or smth else
有传言说可以在Oracle中模拟部分多列(复合)索引。 https://community.oracle.com/ideas/18213
https://blog.jooq.org/2017/01/18/how-to-emulate-partial-indexes-in-oracle/
我是否需要创建一对某种哈希函数
CREATE OR REPLACE FUNCTION get_record_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id <> 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute(city_id, organization_id);
END IF;
END;
CREATE OR REPLACE FUNCTION get_record_department_index (city_id IN NUMBER, organization_id IN NUMBER, department_id IN NUMBER)
RETURN NUMBER
DETERMINISTIC
AS
BEGIN
IF department_id = 0 THEN RETURN NULL
ELSE RETURN no_idea_how_to_compute2(city_id, organization_id, department_id);
END IF;
END;
并创建两个基于函数的索引?
upd: 我需要这样的东西
CREATE INDEX record_main_index ON record (rayon_id, organization_id) WHERE department_id = 0;
CREATE INDEX record_department_index ON record (rayon_id, organization_id, department_id) WHERE department_id <> 0;
答案 0 :(得分:1)
您可以在表中添加一个虚拟列,然后将该列包括在索引中:
ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
CREATE INDEX record_paritial_idx ON record (city_id, organization_id, zero_dept_id);
再三考虑,您可能只需要下面的单列索引而不是上面的多列索引。
CREATE INDEX record_paritial_idx ON record (zero_dept_id);
然后在代码中使用r.department_id = 0
而不是使用r.zero_dept_id = 0
来使用新索引。
不能保证这将改善您的查询性能,但是您可以尝试一下。
对于真正删除所有非零department_id条目的多列索引,您可能需要更多虚拟列:
ALTER TABLE record ADD zero_dept_id AS (CASE department_id WHEN 0 THEN 0 END);
ALTER TABLE record ADD zero_dept_city_id AS (CASE department_id WHEN 0 THEN city_id END);
ALTER TABLE record ADD zero_dept_org_id AS (CASE department_id WHEN 0 THEN organization_id END);
CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id, zero_dept_id);
然后在代码中进行适当的替换以获取此信息:
r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id AND r.zero_dept_id = 0
在上面的最后一个选项中,您可以删除zero_dept_id列,因为当部门id为零时,其他两个虚拟列将仅在索引中具有值,在这种情况下,索引将变为:
CREATE INDEX record_paritial_idx ON record (zero_dept_city_id, zero_dept_org_id);
,查询谓词为:
r.zero_dept_city_id = t.city_id AND r.zero_dept_org_id = t.organization_id
具有虚拟列zero_dept *所隐含的department_id = 0
谓词。