为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】:
【操作系统】:
【CPU】:
【问题描述】:
视图语句:create view view_follow as
(
SELECT t.,
ROW_NUMBER() OVER ( PARTITION BY idcard, disease, TO_CHAR(TIME, 'YYYYMMDD') ORDER BY center ASC) AS rank
FROM (SELECT t.*, concat(idcard, '-', disease, '-', TO_CHAR(t.time, 'YYYYMMDD')) AS agg_idt
FROM (SELECT af.id,
af.idcard,
af.disease,
af.way,
af.weeks,
af.time,
af.plan_time,
NULL AS next_time,
af.utime,
unix_timestamp(af.utime) * 1000 AS utimestamp,
af.status,
af.cid,
af.ctime,
af.sync_state,
af.sync_time,
af.sync_user_id,
NULL AS org_code,
NULL AS org_name,
0 AS center
FROM ai_follow AS af
UNION ALL
SELECT cfh.id,
cfh.idcard,
1 AS "disease",
cfh.way,
cfh.weeks,
cfh.time,
NULL AS plan_time,
cfh.next_time,
cfh.utime,
cfh.utimestamp,
cfh.status,
NULL AS cid,
NULL AS ctime,
NULL AS sync_state,
NULL AS sync_time,
NULL AS sync_useid,
cfh.org_code,
cfh.org_name,
1 AS center
FROM center_follow_hbp AS cfh
UNION ALL
SELECT cfd.id,
cfd.idcard,
2 AS "disease",
cfd.way,
cfd.weeks,
cfd.time,
NULL AS plan_time,
cfd.next_time,
cfd.utime,
cfd.utimestamp,
cfd.status,
NULL AS cid,
NULL AS ctime,
NULL AS sync_state,
NULL AS sync_time,
NULL AS sync_useid,
cfd.org_code,
cfd.org_name,
1 AS center
FROM center_follow_dm AS cfd) AS t) AS t
);
视图大小:1000万条数据
查询语句:select * from view_follow where id = '****'
执行计划:
问题:三张表id主键都是有索引的 为什么一个最简单的根据id查耗时2分钟
可以试试
/+FILTER_PUSH_DOWN(1) VIEW_PULLUP_FLAG(1)/
比如 select /*+ FILTER_PUSH_DOWN(1) VIEW_PULLUP_FLAG(1) */ * from view_follow where id ='条件'
能否将开窗函数从视图里去掉?
这个开窗序号目的是为了查询结果排序,那放到查询里是否可以?
比如:
--原视图修改
create or replace view view_follow as
(
SELECT t.*
--,ROW_NUMBER() OVER ( PARTITION BY idcard, disease, TO_CHAR(TIME, 'YYYYMMDD') ORDER BY center ASC) AS rank
FROM (SELECT t.*
。。。。。。
--查询脚本
SELECT *
,ROW_NUMBER() OVER ( PARTITION BY idcard, disease, TO_CHAR(TIME, 'YYYYMMDD') ORDER BY center ASC) AS rank
FROM view_follow
WHERE ID = 1
是期望这样的执行计划嘛?
select t.*, rownumber() ...
from
select t.*, concat(...)
from (
...A... -- 走索引 扫描 [id,id]
union all
...B... -- 走索引 扫描 [id,id]
union all
...C... -- 走索引 扫描 [id,id]
) t
) t
这就错了,和原语句查询的结果不一样。根本原因在视图存在窗口函数有分组计算,如果走索引提前把数据筛选了再做开窗函数,计算的结果就错了。举个例子,查询一个人的工资信息(包含自己的工资,所在部门的平均薪资,所在在部门的薪资排行or公司的平均薪资,在整个公司的平均薪资排行),这得访问薪资表所有记录才能得出正确结果。
因此,这种需求下优化器选择全扫描是正确的,如果强行指定id列索引也能查询出正确结果,只是需要通过id回表绕了个弯。当然,每次全表扫描也是不合适的,尤其是查询频率高的SQL。
还是有加速的解决办法:
1、新增3个表的覆盖索引--用于快速计算rank
create index idx_ai_follow_1129 on ai_follow(id,idcard,disease,TIME);
create index idx_center_follow_hbp_1129 on center_follow_hbp(id,idcard,TIME);
create index idx_center_follow_dm_1129 on center_follow_dm(id,idcard,TIME);
2、新建视图--前半部分t1计算出每个id的rank,后半部分用于关联表找到id对应明细,建议ID列设计为聚集索引(无大字段情况时)
create view view_follow as
SELECT t2.*, t1.rank
from (
SELECT t1.id,
ROW_NUMBER() OVER (
PARTITION BY t1.idcard,
t1.disease,
TO_CHAR(t1.TIME, 'YYYYMMDD')
ORDER BY t1.center ASC) AS rank
FROM (SELECT af.id,
af.idcard,
af.disease,
af.time,
0 AS center
FROM ai_follow AS af
UNION ALL
SELECT cfh.id,
cfh.idcard,
1 AS "disease",
cfh.time,
1 AS center
FROM center_follow_hbp AS cfh
UNION ALL
SELECT cfd.id,
cfd.idcard,
2 AS "disease",
cfd.time,
1 AS center
FROM center_follow_dm AS cfd
) AS t
) t1
join
(
SELECT t.*,
concat(idcard, '-', disease, '-', TO_CHAR(t.time, 'YYYYMMDD')) AS agg_idt
FROM (SELECT af.id,
af.idcard,
af.disease,
af.way,
af.weeks,
af.time,
af.plan_time,
NULL AS next_time,
af.utime,
unix_timestamp(af.utime) * 1000 AS utimestamp,
af.status,
af.cid,
af.ctime,
af.sync_state,
af.sync_time,
af.sync_user_id,
NULL AS org_code,
NULL AS org_name,
0 AS center
FROM ai_follow AS af
UNION ALL
SELECT cfh.id,
cfh.idcard,
1 AS "disease",
cfh.way,
cfh.weeks,
cfh.time,
NULL AS plan_time,
cfh.next_time,
cfh.utime,
cfh.utimestamp,
cfh.status,
NULL AS cid,
NULL AS ctime,
NULL AS sync_state,
NULL AS sync_time,
NULL AS sync_useid,
cfh.org_code,
cfh.org_name,
1 AS center
FROM center_follow_hbp AS cfh
UNION ALL
SELECT cfd.id,
cfd.idcard,
2 AS "disease",
cfd.way,
cfd.weeks,
cfd.time,
NULL AS plan_time,
cfd.next_time,
cfd.utime,
cfd.utimestamp,
cfd.status,
NULL AS cid,
NULL AS ctime,
NULL AS sync_state,
NULL AS sync_time,
NULL AS sync_useid,
cfd.org_code,
cfd.org_name,
1 AS center
FROM center_follow_dm AS cfd) AS t
) t2
on t2.id = t1.id
;
3、查询
select /*+ view_pullup_flag(1) filter_push_down(1) enable_hash_join(0) */ * from view_follow where id = ?
以上,缺少环境未经验证(可能存在一些小错误需纠正),但提供了一个思路。您可以验证下效果,预计10s这样是可以的。
执行计划右上角有个显示方式选择文本显示