[英]nested query performance alternatives
從性能角度來看 ,這是編寫以下有關嵌套查詢的查詢的最佳方法:
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)
這里任何建議的表現將取決於很多:
- 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
;
你可以嘗試這個 -
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;
如果可以避免相關子查詢,則性能越好,非相關子查詢的示例:
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)
我寧願創建一個臨時表來查找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)
無論如何我不喜歡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 OR 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)
看起來查詢將訪問表中的大部分數據(如果不是直接進行全表掃描)。 如果是這樣,我建議完全避免相關子查詢,因為它們最多只能執行索引。 嘗試將其重新編寫為如下所示的簡單連接,前半部分只需找到每個員工的最大年/月,然后將其用作針對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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.