【问题标题】:SQL optimize inner join (Inner join with union and possible use of subquery)SQL 优化内连接(内连接与联合和可能使用子查询)
【发布时间】:2017-09-12 19:26:14
【问题描述】:

我有两个表——Test,Child,其中包含版本化数据。 列说明:

TEST, CHILD Table
ID - Record id (not unique due to multiple versions)
MODSTAMP - Timestamp at which record is inserted
DELETEDDATE - Timestamp at which record is deleted; NULL value means record is not deleted yet.
COMPOSITE KEY = {ID, MODSTAMP}

CHILD Table
DATA - Foreign key that references Test(ID)
DATA2 - Foreign key that references Test(ID)

我正在处理在两个时间戳之间选择记录的要求 - $FROMTIME 和 $TOTIME。我可以通过运行自联接来选择 Test 表上的记录。

SELECT v.id, v.modstamp FROM test v
INNER JOIN
    (SELECT Id, MAX(modstamp) AS MaxDateTime
    FROM test where modstamp >= '2017-08-16 15:08:04 +00:00' and modstamp <= '2017-08-16 17:08:04 +00:00' GROUP BY Id) g 
ON v.Id = g.Id 
AND v.modstamp = g.MaxDateTime where v.deleteddate is null

我还需要选择为其选择父记录的相应子记录的最新版本(没有任何重复的记录 id 和 group by 子句)。我的应用程序保存了上述查询的结果并运行以下查询来为每个值 ['aaa', 'bbb'] 选择有效的子记录:

 SELECT v.* FROM child v
    INNER JOIN
        (SELECT id, MAX(modstamp) AS MaxDateTime
        FROM child where (data = ? or data is null) and modstamp <= '2017-08-16 17:08:04 +00:00' GROUP BY id
            UNION
        SELECT id, MAX(modstamp) AS MaxDateTime
        FROM child where (data2 = ? or data2 is null) and modstamp <= '2017-08-16 17:08:04 +00:00' GROUP BY id
        ) g 
    ON v.id = g.id 
    AND v.modstamp = g.MaxDateTime

谁能建议如何优化这个解决方案?使用当前方法,如果选择了 n 个父记录,则将有 n 个内部连接将运行。

这是用于连接但抛出“未找到多部分标识符错误”的查询。还有其他方法可以重写查询吗? -- 预期查询

SELECT v.* FROM child v
    INNER JOIN (select distinct(id) from DATA) D
    ON v.id = D.id
    INNER JOIN
        (SELECT id, MAX(modstamp) AS MaxDateTime
        FROM child where (data = d.id or data is null) and modstamp <= '2017-08-16 17:08:04 +00:00' GROUP BY id
            UNION
        SELECT id, MAX(modstamp) AS MaxDateTime
        FROM child where (data2 = d.id or data2 is null) and modstamp <= '2017-08-16 17:08:04 +00:00' GROUP BY id
        ) g 
    ON v.id = g.id 
    AND v.modstamp = g.MaxDateTime;

运行脚本的示例信息:

Test
| ID | MODSTAMP | DELETEDDATE |

Child
| ID | DATA | DATA2 | MODSTAMP | DELETEDDATE |

脚本(使用 SQL Server):

drop table test;
drop table child;

CREATE TABLE TEST(ID VARCHAR(20), modstamp DATETIMEOFFSET, deleteddate DATETIMEOFFSET);
insert into test values('aaa', '2017-08-16 15:08:04 +00:00', null);
insert into test values('aaa', '2017-08-16 16:08:04 +00:00', null);
insert into test values('aaa', '2017-08-16 17:08:04 +00:00', null);
insert into test values('aaa', '2017-08-16 18:08:04 +00:00', '2017-08-16 18:08:04 +00:00');
insert into test values('bbb', '2017-08-16 17:08:04 +00:00', null);

CREATE TABLE CHILD(ID VARCHAR(20), DATA VARCHAR(10), DATA2 VARCHAR(10), modstamp DATETIMEOFFSET, deleteddate DATETIMEOFFSET);
insert into CHILD values('1', 'aaa', null, '2017-08-16 15:08:04 +00:00', null);
insert into CHILD values('1', null, 'bbb', '2017-08-16 16:08:04 +00:00', null);
insert into CHILD values('1', null, null, '2017-08-16 17:08:04 +00:00', null);
insert into CHILD values('2', 'aaa', null, '2017-08-16 15:08:04 +00:00', null);
insert into CHILD values('3', null, null, '2017-08-16 15:08:04 +00:00', null);

【问题讨论】:

  • 您是否正在寻找一种更短的方式来编写这个?我不明白这个问题。
  • 是的。我希望优化父记录 id 列表('aaa'、'bbb')的子记录选择。
  • row_number 将比最大聚合快。
  • 不知何故我不明白这个问题:你说你想选择两个日期之间的记录,但只选择最大值(modstamp)。此外,您写道,您保存第一个查询的记录,并通过传递参数执行第二个查询......所以,除非您想重新设计整个过程 - 预期结果是什么?如果您想跳过此“评估父记录并将它们传递给第二个查询”,您可以简单地使用 cte 并将其加入您的子表...
  • @Tyron78 在子表上使用 CTE 和连接是错误的,因为它包含版本化数据。想象一下在给定时间戳范围内获取最新记录,因为可能存在相同记录 ID 的多个版本。

标签: sql sql-server join


【解决方案1】:

您的查询看起来不错。我不会将以下查询称为优化,但另一种方法是使用ROW_NUMBER()

SELECT * FROM (
SELECT *, rownum = ROW_NUMBER() OVER (PARTITION BY id ORDER BY modstamp)
FROM child
WHERE (data = ? OR data IS NULL OR data2 = ? OR data2 IS NULL) AND modstamp <= '2017-08-16 17:08:04 +00:00'
) AS a where rownum = 1

【讨论】:

    猜你喜欢
    • 2012-03-16
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多