首页 > 解决方案 > 提高 sql 查询性能以比较使用同一列的 2 个不同行而不是加入另一个表

问题描述

在此处输入图像描述我有一张桌子叫Status. 在此表中,可以有 2 条记录,每个记录的状态为“ A”和“ Oc_number。每个的许多记录c_number都在NUMBER表中。表中带' 'record_date的记录字段必须大于带'的记录的字段,并且必须在指定日期之间。另外,表中应该有一条带有' ''的记录。为此,我准备了以下查询。如何在没有索引的情况下提高查询性能?每个表都有数百万条记录。c_number'sOStatusrecord_datec_number'sA'record_datec_number'srecord_status1NUMBER

SELECT 
    d.id, 
    d.c_number, 
    d.record_date, 
    dup.record_date 
FROM 
    dbo.STATUS (nolock) as d 
INNER JOIN 
    (SELECT DISTINCT 
         c_number, 
         record_date 
     FROM 
         dbo.STATUS (NOLOCK) 
     WHERE 
         record_status = 'O' 
         and record_date between '2021-07-01 00:00:00.000' 
         and '2021-07-24 23:59:59.00') dup ON dup.c_number = d.c_number 
                                           AND d.record_status = 'A' 
                                           AND dup.record_date >= d.record_date 
INNER JOIN 
    (SELECT DISTINCT c_number 
     FROM dbo.NUMBERS (NOLOCK) 
     WHERE 
         status_flag = '1' 
         AND record_date between '2021-07-01 00:00:00.000' 
         AND '2021-07-24 23:59:59.00') cc ON cc.c_number = d.c_number

标签: sqlsql-server

解决方案


您可以使用条件窗口函数来获得您需要的结果,无需自连接。

进一步说明:

  • 除非您不介意不正确的结果,否则请勿使用。NOLOCK它有严重的后果,只有在你真的知道自己在做什么的情况下才使用它
  • 而不是BETWEEN日期,而是使用半开间隔>= AND <。这意味着您无需在一天中的最后一毫秒搞定
  • 在很多情况下,半连接EXISTSIN半连接比不同连接更好,并且让编译器可以更自由地重新排列查询
SELECT 
    d.id, 
    d.c_number, 
    d.record_date, 
    oRecordDate
FROM (
    SELECT *,
        oRecordDate = MIN(CASE WHEN d.record_status = 'O' THEN d.record_date END) OVER
            (PARTITION BY d.c_number ORDER BY d.record_date ROWS UNBOUNDED FOLLOWING)
    FROM dbo.STATUS d
) d
WHERE d.c_number IN (
    SELECT cc.c_number
    FROM dbo.NUMBERS cc
    WHERE 
        cc.status_flag = '1' 
    AND cc.record_date >= '2021-07-01'
    AND cc.record_date <  '2021-07-25'
)
AND d.record_date >= '2021-07-01'
AND d.record_date <  '2021-07-25'
AND d.record_status = 'A';

推荐阅读