问题描述
假设我们有下表(所有需要的行都标有*):
col1 col2 col3
---------------------------------------------------------
002478 ABC 2019-08-23 *
002478 ABC 2019-05-14
002588 CVMG 2019-01-07 *
002588 IP 2019-01-31 *
002588 MMG 2019-09-04 *
002588 MMG 2019-08-28
002588 NUSA 2019-11-04 *
002588 NUSA 2019-04-24
002746 IE 2019-01-15 *
003467 IE 2020-01-10
003467 IE 2020-03-13 *
通过以下选择,我能够获得基于col1和col2的最新事件。
SELECT t.col1,t.col2,t.col3
FROM
teste t
WHERE t.col3 IN (SELECT max(a.col3)
FROM teste a
WHERE a.col1 = t.col1 AND a.col2 = t.col2)
在此示例中,只需大约10 ~ 7 ms
即可完成,但是在我的真实数据库中,大约需要1 hour
。
我删除了所有可能的JOINS
,并且我到达的最短时间约为55 minutes
。
使用Progress时,没有window function
这样的partition by
(我知道)。
还有另一种方法可以解决此问题?我唯一想到的查询就是关于“样式”的。
这是该示例数据库的SQL Fiddle。
解决方法
编写同一查询的另一种方法是选择不存在较新的相关行的行:
SELECT t.col1,t.col2,t.col3
FROM teste t
WHERE NOT EXISTS
(
SELECT NULL
FROM teste t_newer
WHERE t_newer.col1 = t.col1
AND t_newer.col2 = t.col2
AND t_newer.col3 > t.col3
);
这可能更快或更慢或同样快。这取决于您的DBMS在内部如何运行。
使用这两个查询中的任何一个,DBMS都面临着快速查找具有相同col1和col2的其他行的任务。仅使用该表,DBMS将不得不一次又一次地依次读取它。这就是索引起作用的地方。您可以为DBMS提供索引,在其中可以查找表中匹配行的位置。
在您的情况下,您需要一个索引col1和col2,以便提供一种查找相关行的方法。您还可以添加col3,因为这也必须进行比较。也许以col1或col2开始索引并不重要,也许确实如此。表中有多少个不同的col1,有多少个不同的col2?如果一个只有5个不同的值,而另一个只有5,000个,则从一个有5,000个值的索引开始,因为对于一个值,您会发现较少的行,即更快地找到了感兴趣的行。
索引可能看起来像
create index idx on teste (col1,col2,col3);
查询保持不变。 DBMS将查看您的查询并决定是否使用索引。对于给定的查询,我确定它将使用提到的索引,因为查询都是为了快速查找相关行。