5

性能的角度来看,这是编写有关嵌套查询的以下查询的最佳方式:


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)
4

6 回答 6

2

你可以试试这个——

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;
于 2013-10-24T11:31:24.763 回答
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
;
于 2013-10-27T16:21:15.007 回答
2

在任何情况下,我都不喜欢 Co-related Sub 查询。从评论中我看到这是针对 INFORMIX 而不是针对 SQL,因此我建议将 JOIN 与嵌套选择一起用作首选。这样做的好处是这些是编写查询的非常原生的方式,并且您可以期望数据库优化器使用索引(如果可用)提出良好的执行计划。在 SQL 中,如果我的表不在数百万行中,我会选择 CTE。我假设您在表上有适当的索引。如果不确定您在表上有以下索引。

注意索引中列的顺序及其 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)”条件。即使在嵌套的选择语句中,也允许查询减少结果集中需要的行数。另请注意,查询中在 Where 和 JOIN 条件中提到的列与索引中的列顺序匹配。

我留给你尝试的一件事是

“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)
于 2013-11-01T20:10:16.670 回答
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而不是AND的类似非相关JOIN,使用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)
于 2013-10-27T11:43:16.570 回答
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)
于 2013-10-30T11:04:16.033 回答
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;
于 2013-11-03T07:00:34.217 回答