从性能角度,这是编写以下有关嵌套查询的查询的最佳方式:
SELECT a.meg,a.currency
FROM alt6sal a
WHERE a.meg_code IN (1,2)
AND a.sal_year = (SELECT MAX(ia.sal_year) FROM alt6sal ia WHERE a.emp_num = ia.emp_num )
AND a.sal_mon = (SELECT MAX(ia.sal_mon) FROM alt6sal ia WHERE a.emp_num = ia.emp_num AND a.sal_year = ia.sal_year)
答案 0 :(得分:2)
这里任何建议的表现将取决于很多:
- 您的Informix引擎版本(语法可能不适用于版本< 11.50)
- 过滤索引
- 数据量
- 更新了表/索引统计信息
这将强制数据库首先使用所有sal_year创建一个临时表,然后与主表联接...
建议1)
SELECT a.meg,a.currency
FROM alt6sal a
,(SELECT emp_num, MAX(ia.sal_year) sal_year FROM alt6sal ia group by 1 ) as a2
WHERE a.meg_code IN (1,2)
AND a.sal_year = a2.sal_year and a.emp_num = a2.emp_num
AND a.sal_mon = (SELECT MAX(ia.sal_mon) FROM alt6sal ia WHERE a.emp_num = ia.emp_num AND a.sal_year = ia.sal_year)
建议2)
SELECT a.meg,a.currency
FROM alt6sal a
,(SELECT aa.emp_num, MAX(aa.sal_year) sal_year FROM alt6sal aa where aa.meg_code in (1,2) group by 1 ) as a2
,(SELECT ab.emp_num, ab.sal_year, max(ab.sal_mon) sal_mon FROM alt6sal ab where ab.meg_code in (1,2)group by 1,2 ) as a3
WHERE a.meg_code IN (1,2)
AND a.sal_year = a2.sal_year and a.emp_num = a2.emp_num
and a.sal_mon = a3.sal_mon AND a.sal_year = a2.sal_year and a.emp_num = a2.emp_num
;
答案 1 :(得分:1)
你可以试试这个 -
SELECT meg, currency
FROM
(
SELECT a.meg,a.currency,
dense_rank() over (PARTITION BY a.emp_num ORDER BY a.sal_year desc) year_rank,
dense_rank() over (PARTITION BY a.emp_num ORDER BY a.sal_mon desc) mon_rank
FROM alt6sal a
WHERE a.meg_code IN (1,2)
)
WHERE year_rank = 1
AND mon_rank = 1;
答案 2 :(得分:1)
如果可以避免相关子查询,性能越好,非相关子查询的示例:
SELECT a.meg,a.currency
FROM alt6sal a
join
(
select ia.emp_num, max(ia.sal_year) as sal_year_max
from alt6sal ia
group by ia.emp_num
) the_year_max
on a.emp_num = the_year_max.emp_num and a.sal_year = the_year_max.sal_year_max
join
(
select ia.emp_num, ia.sal_year, max(ia.sal_mon) as sal_mon_max
from alt6sal ia
group by ia.emp_num, ia.sal_year
) the_month_max
on a.emp_num = the_month_max.emp_num and a.sal_year = the_month_max.sal_year
and a.sal_mon = the_month_max.sal_mon_max
WHERE a.meg_code IN (1,2)
OR的类似非相关JOINS而不是AND,使用LEFT JOIN然后过滤非空
SELECT a.meg,a.currency
FROM alt6sal a
left join
(
select ia.emp_num, max(ia.sal_year) as sal_year_max
from alt6sal ia
group by ia.emp_num
) the_year_max
on a.emp_num = the_year_max.emp_num and a.sal_year = the_year_max.sal_year_max
left join
(
select ia.emp_num, ia.sal_year, max(ia.sal_mon) as sal_mon_max
from alt6sal ia
group by ia.emp_num, ia.sal_year
) the_month_max
on a.emp_num = the_month_max.emp_num and a.sal_year = the_month_max.sal_year
and a.sal_mon = the_month_max.sal_mon_max
WHERE a.meg_code IN (1,2)
and
(the_year_max.ia_emp_num is not null
or the_month_max.ia_emp_num is not null)
答案 3 :(得分:1)
我宁愿创建一个临时表来查找MAX值,并且可能会减少锁定,因为您在表上执行了2次单独读取而不是3次并发读取。
/*create @table to keep uniqe records for empnum, salaryyear, salarymonth*/
DECLARE @maxyearstage TABLE(empnum BIGINT, combo DATETIME);
DECLARE @maxyear TABLE(empnum BIGINT, [year] INT, [month] TINYINT);
INSERT INTO @maxyearstage
SELECT DISTINCT my.emp_num
, CAST(CONVERT(VARCHAR(my.sal_year)+'-'+CONVERT(VARCHAR(my.sal_month)+'-'+'01' [combo]
FROM alt6sal my;
INSERT INTO @maxyear
SELECT t3.empnum, YEAR(t3.combo), MONTH(t3.combo)
FROM ( SELECT T2.empnum, MAX(T2.combo) combo FROM @maxyear T2 GROUP BY T2.empnum) t3;
SELECT a.meg,a.currency
FROM alt6sal a
INNER JOIN @maxyear t1 ON t1.empnum = a.empnum AND t1.[year] = a.sal_year AND t1.[month] = a.sal_mon
WHERE a.meg_code IN (1,2)
答案 4 :(得分:1)
在任何情况下我都不会喜欢与Co相关的Sub查询。从评论我看到这是为INFORMIX而不是SQL,因此我建议使用JOIN与嵌套选择作为第一选择。这样做的好处是那些非常本地的编写查询的方式,你可以期望DB优化器使用索引(如果可用)提出良好的执行计划。 在SQL中,如果我的表不是数百万行,我会选择CTE。我假设你在桌子上有适当的索引。如果没有,请确保您在表格中有以下索引。
注意Index中的列顺序及其ASC / DESC顺序。
CREATE CLUSTER INDEX IDXc_alt6sal
ON alt6sal ( meg_code ASC,
sal_year DESC,
sal_mon DESC,
emp_num ASC
)
CREATE INDEX IDXnc_alt6sal
ON alt6sal ( meg_code ASC,
sal_year DESC,
sal_mon DESC,
emp_num ASC
) INCLUDE (meg,currency)
现在测试以下查询。请注意我已添加" meg_code IN(1,2)"当我使用实际表时,所有选择条件。这允许查询减少结果集中需要的行数,即使在嵌套的select语句中也是如此。还要注意Query中的Where和JOIN条件中提到的列,并与Indexes中的列顺序匹配。
我留给你的一件事是
" meg_cod = 1或meg_cod = 2"
改为
" meg_code IN(1,2)"
并查看效果是否明显改善。我知道如果它是SQL它没有任何区别,但对于INFORMIX我不是100%肯定。
SELECT t1.meg,t1.currency,t1.emp_num
FROM alt6sal t1
JOIN
(
Select yer.emp_num,yer.sal_year,MAX(mth.sal_mon) AS sal_mon
FROM
( SELECT emp_num, MAX(sal_year) AS sal_year
FROM alt6sal
WHERE meg_code IN ( 1, 2 )
GROUP BY emp_num
)yer
JOIN alt6sal mth
ON yer.sal_year = mth.sal_year AND yer.emp_num=mth.emp_num
AND mth.meg_code IN (1,2)
GROUP BY yer.sal_year,yer.emp_num
)t2
ON t1.sal_year=t2.sal_year AND t1.sal_mon=t2.sal_mon AND t1.emp_num=t2.emp_num
AND t1.meg_code IN (1,2)
答案 5 :(得分:1)
看起来查询将访问表中的大部分数据(如果不是直接进行全表扫描)。如果是这样,我建议完全避免相关子查询,因为它们最多只能执行索引。尝试将其重新编写为如下所示的简单连接,前半部分只需查找每个员工的最大年/月,然后将其用作针对alt6sal的连接过滤器。
SELECT a.meg,a.currency
FROM alt6sal a,
(SELECT MAX(ia.sal_year || '-' || ia.sal_mon) max_sal_year_mon, ia.emp_num ia_emp_num FROM alt6sal ia where ) ia
WHERE a.meg_code IN (1,2)
AND (a.sal_year||'-'||a.sal_mon) = max_sal_year_mon
AND ia_emp_num = emp_num;