我有一个表,表有超过7000万行。如果我执行此查询,则需要大约1581秒才能完成。如何优化此查询?而且该表是日志表。该表没有任何索引。有什么建议吗?
select a.volumeOfUser_Show_Psg, b.volumeOfUser_Continue_Psg, (a.volumeOfUser_Show_Psg - b.volumeOfUser_Continue_Psg) as totalNumberCancleProgressSaver
from
(select Count(R_CRE_ID) as volumeOfUser_Show_Psg from CADT where CUR_REC like 'Show_Progress_Saver%'
and CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate) a,
(select Count(R_CRE_ID) as volumeOfUser_Continue_Psg from CADT where CUR_REC like 'Continue_Progress_Saver%'
and CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate) b;
答案 0 :(得分:1)
现在我看到以下问题:
到目前为止,您投出了2.4亿个值;你可以避免这样做
您在此表中没有索引
如果可以执行一次
要解决这些问题:
创建持久计算列,其值为r_cre_id的日期转换版本。这意味着演员操作将在插入时发生一次,而不是每次运行查询时都会发生..
在一个索引中将COMPUTED COLUMN和cur_rec列一起索引。这是您将获得的单一最大性能提升,因为您将拥有涵盖整个查询的索引
通过这种模式点击表/索引一次:
查询
SELECT
count(case when cur_rec like 's%' then 1 end) as count_show,
count(case when cur_rec like 'c%' then 1 end) as count_cont
FROM
table
WHERE
computed_column_date BETWEEN @fromdate and @todate ANd
(Cur_rec like 'continue_progress_saver%' or cur_rec like 'show_progress_saver%')
不要跳过计算列。不要使用时间组件索引日期列(如果索引较小,则此索引的性能会更好,这意味着通过减少粒度来索引更少的唯一值)。仅创建日期部分的计算列并将其编入索引。如果您执行此操作,此查询将在几秒钟内返回结果
注意,如果你的cur_rec列也是高度变化的(即它包含超过一百万个唯一值),你应该考虑创建函数LEFT(cur_rec, 20)
的结果的另一个计算列,改为索引这个计算列,并且使您的查询看起来像:
SELECT
count(case when computed_column_left20currec like 's%' then 1 end) as count_show,
count(case when computed_column_left20currec like 'c%' then 1 end) as count_cont
FROM
table
WHERE
computed_column_date BETWEEN @fromdate and @todate AND
computed_column_left20currec in ('show_progress_saver','continue_progress_s')
我之所以建议为这些列制作计算列,是因为这些计算列的唯一值要少得多。这意味着任何生成的索引都具有较少的键。如果我们所做的只是计算,最好不要计算每个引用一行的数亿个索引键,以获得总数。
有关创建计算列的信息,请参阅以下内容:
答案 1 :(得分:0)
WITH AS
WITH Data (volumeOfUser_Show_Psg, volumeOfUser_Continue_Psg)
AS
(
SELECT Count(1) AS volumeOfUser_Show_Psg, 0 AS volumeOfUser_Continue_Psg
FROM CADT
WHERE CUR_REC LIKE 'Show_Progress_Saver%' AND CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate
UNION
SELECT Count(1) AS volumeOfUser_Show_Psg, 0 AS volumeOfUser_Continue_Psg
FROM CADT
WHERE CUR_REC LIKE 'Continue_Progress_Saver%' AND CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate
)
SELECT SUM(volumeOfUser_Show_Psg), SUM(volumeOfUser_Continue_Psg), (SUM(volumeOfUser_Show_Psg) - SUM(volumeOfUser_Continue_Psg)) as totalNumberCancleProgressSaver
FROM Data
案例:
WITH Data (volumeOfUser_Show_Psg, volumeOfUser_Continue_Psg)
AS
(
SELECT SUM(CASE WHEN CUR_REC LIKE 'Show_Progress_Saver%' THEN 1 ELSE 0 END) AS volumeOfUser_Show_Psg, SUM(CASE WHEN CUR_REC LIKE 'Continue_Progress_Saver%' THEN 1 ELSE 0 END) AS volumeOfUser_Continue_Psg
FROM CADT
WHERE CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate
)
SELECT volumeOfUser_Show_Psg, volumeOfUser_Continue_Psg, (volumeOfUser_Show_Psg - volumeOfUser_Continue_Psg) as totalNumberCancleProgressSaver
FROM Data
但无论如何,您是否为C_CRE_TIME创建了一个索引,并且可能与CUR_REC结合使用?那个施放日期可能很糟糕,为什么需要呢?
答案 2 :(得分:0)
如果能提供性能,请你试试下面的
SELECT volumeofuser_show_psg, volumeofuser_continue_psg,
( volumeofuser_show_psg - volumeofuser_continue_psg ) AS
totalNumberCancleProgressSaver
(
SELECT
COUNT(CASE WHEN cur_rec LIKE 'Show_Progress_Saver%' then 1 ELSE NULL END) as "volumeofuser_show_psg",
COUNT(CASE WHEN cur_rec LIKE 'Continue_Progress_Saver%' then 1 ELSE NULL END) as "volumeofuser_continue_psg"
FROM cadt
WHERE Cast(r_cre_time AS DATE) >= @fromDate
AND Cast(r_cre_time AS DATE) <= @toDate)
) T;
答案 3 :(得分:0)
你的意思是做笛卡尔式的加入吗?
即。 from a,b
Here's a nice reference of how this join would work
如果你没有,这可能会提供你想要的东西:
select a.volumeOfUser_Show_Psg,
a.volumeOfUser_Continue_Psg,
(a.volumeOfUser_Show_Psg - a.volumeOfUser_Continue_Psg) as totalNumberCancleProgressSaver
from(
select sum(case when cur_rec like 'Show%' then 1 else 0 end) as volumeOfUser_Show_Psg,
sum(case when cur_rec like 'Cont%' then 1 else 0 end) as count_cont as volumeOfUser_Continue_Psg
from CADT
where (CUR_REC like 'Show_Progress_Saver%' or CUR_REC like 'Continue_Progress_Saver%')
and CAST(R_CRE_TIME AS DATE) >= @fromDate and CAST(R_CRE_TIME AS DATE) <= @toDate)
) a;
这能为您提供所需的结果吗?
提示,尝试格式化代码,使语句分开。这使得代码更容易阅读。
每个记录的转换将影响性能,最好将@fromDate和@toDate更改为与R_CRE_TIME相同。 如果可能,请在表上创建索引。这将有很大帮助。
如果没有关于数据的更多信息,涉及的表格或意图没有太多其他内容可以添加。