连接表的最后记录(如何优化)

时间:2009-09-09 14:26:10

标签: sql

我有(Last record of Join table)中描述的相同“问题”:我需要加入“主表”和“历史表”,而我只想加入最新的(按日期)记录历史表。因此,每当我查询可记录的记录时,我也会记录历史表的“最新”数据。

Master Table
  ID
  FIRSTNAME
  LASTNAME
  ...

History Table
  ID
  LASTACTION
  DATE

这可以通过连接两个表并使用子选择来检索最新的历史记录表记录,如上面链接中给出的答案中所述。

我的问题是: 我怎样才能解决问题,理论上可能有两个具有相同日期的历史记录?

这种与subselect的加入真的是性能方面(一般而言)的最佳解决方案吗?如果我将历史表中另一个名为“ISLATESTRECORD”的属性集成为我手动管理的布尔标志(并且具有唯一约束),您认为(我不是所有这些东西的专家)。然后,此属性将显式标记最新记录,我不需要任何子选择,因为我可以在连接的where子句中直接使用此属性。 另一方面,这使得插入新记录当然有点复杂:我首先必须从最新记录中删除“ISLATESTRECORD”标志,我必须插入带有“ISLATESTRECORD”设置和提交的新历史记录交易。

您认为推荐的解决方案是什么?我对子选择的性能影响没有任何线索:我可能有数以百万计的“Mastertable”记录“我必须在连接的历史表的搜索属性中搜索特定记录,如:”给我使用FIRSTNAME XYZ和LASTACTION(历史记录表)的Mastertable记录是“changed_name”。所以这个子选择可能被称为数百万次。

或者用subselect更好地找到最新记录,因为子选择非常有效并且更好地保持一切正常化?

非常感谢

2 个答案:

答案 0 :(得分:2)

我通过对现有表的查询以及在历史表中添加了自动递增标识列的表来解决您的问题。通过在历史记录表中添加自动递增标识列,您可以解决日期的独特问题,并使查询更容易。

解决表的问题(使用SQL Server示例代码):

DECLARE @MasterTable table (MasterID int,FirstName varchar(20),LastName varchar(20))
DECLARE @HistoryTable table (MasterID int,LastAction char(1),HistoryDate datetime)

INSERT INTO @MasterTable VALUES (1,'AAA','aaa')
INSERT INTO @MasterTable VALUES (2,'BBB','bbb')
INSERT INTO @MasterTable VALUES (3,'CCC','ccc')

INSERT INTO @HistoryTable VALUES (1,'I','1/1/2009')
INSERT INTO @HistoryTable VALUES (1,'U','2/2/2009')
INSERT INTO @HistoryTable VALUES (1,'U','3/3/2009')  --<<dups
INSERT INTO @HistoryTable VALUES (1,'U','3/3/2009')  --<<dups
INSERT INTO @HistoryTable VALUES (2,'I','5/5/2009')
INSERT INTO @HistoryTable VALUES (3,'I','7/7/2009')
INSERT INTO @HistoryTable VALUES (3,'U','8/8/2009')

SELECT
    MasterID,FirstName,LastName,LastAction,HistoryDate
    FROM (SELECT
              m.MasterID,m.FirstName,m.LastName,h.LastAction,h.HistoryDate,ROW_NUMBER() OVER(PARTITION BY m.MasterID ORDER BY m.MasterID) AS RankValue
              FROM @MasterTable m
                  INNER JOIN (SELECT
                                  MasterID,MAX(HistoryDate) AS MaxDate
                                  FROM @HistoryTable
                                  GROUP BY MasterID
                             ) dt ON m.MasterID=dt.MasterID
                  INNER JOIN @HistoryTable h ON dt.MasterID=h.MasterID AND dt.MaxDate=h.HistoryDate
         ) AllRows
    WHERE RankValue=1

输出:

MasterID    FirstName LastName LastAction HistoryDate
----------- --------- -------- ---------- -----------
1           AAA       aaa      U          2009-03-03 
2           BBB       bbb      I          2009-05-05 
3           CCC       ccc      U          2009-08-08 

(3 row(s) affected)

使用更好的HistoryTable(使用SQL Server示例代码)解决问题: 它更好,因为它有一个自动递增的历史ID标识列

DECLARE @MasterTable table (MasterID int,FirstName varchar(20),LastName varchar(20))
DECLARE @HistoryTableNEW table (HistoryID int identity(1,1), MasterID int,LastAction char(1),HistoryDate datetime)

INSERT INTO @MasterTable VALUES (1,'AAA','aaa')
INSERT INTO @MasterTable VALUES (2,'BBB','bbb')
INSERT INTO @MasterTable VALUES (3,'CCC','ccc')

INSERT INTO @HistoryTableNEW VALUES (1,'I','1/1/2009')
INSERT INTO @HistoryTableNEW VALUES (1,'U','2/2/2009')
INSERT INTO @HistoryTableNEW VALUES (1,'U','3/3/2009')  --<<dups
INSERT INTO @HistoryTableNEW VALUES (1,'U','3/3/2009')  --<<dups
INSERT INTO @HistoryTableNEW VALUES (2,'I','5/5/2009')
INSERT INTO @HistoryTableNEW VALUES (3,'I','7/7/2009')
INSERT INTO @HistoryTableNEW VALUES (3,'U','8/8/2009')

SELECT
    m.MasterID,m.FirstName,m.LastName,h.LastAction,h.HistoryDate,h.HistoryID
    FROM @MasterTable m
        INNER JOIN (SELECT
                        MasterID,MAX(HistoryID) AS MaxHistoryID
                        FROM @HistoryTableNEW
                        GROUP BY MasterID
                   ) dt ON m.MasterID=dt.MasterID
        INNER JOIN @HistoryTableNEW h ON dt.MasterID=h.MasterID AND dt.MaxHistoryID=h.HistoryID

输出:

MasterID    FirstName LastName LastAction HistoryDate             HistoryID
----------- --------- -------- ---------- ----------------------- ---------
1           AAA       aaa      U          2009-03-03 00:00:00.000 4
2           BBB       bbb      I          2009-05-05 00:00:00.000 5
3           CCC       ccc      U          2009-08-08 00:00:00.000 7

(3 row(s) affected)

答案 1 :(得分:0)

如果历史表具有主键(并且所有表都应该),则可以修改子选择以使用与日期条件匹配的倍数的较大(或较小)PK值来提取记录... < / p>

  Select M.*, H.* 
  From Master M
     Join History H 
         On H.PK = (Select Max(PK) From History
                    Where FK = M.PK
                       And Date = (Select Max(Date) From History
                                   Where FK = M.PK))

关于性能,可以通过向这些表(History.Date,History.FK)添加适当的索引来解决这个问题,但通常,根据特定的表数据分布模式,子查询会对性能产生负面影响。