在 SELECT 语句中使用子查询提高查询性能

问题描述 投票:0回答:1

我已经编写了一个报告查询,该查询旨在从系统事务日志(transaction_log)中提取一些信息,同时还从第二个表(location_table)中查找主值 - 这并不总是存在,有时master_location 或 location_id 字段可以为 NULL。

我提出了下面的查询,它产生了我想要的结果,尽管自从将“master_location”列添加到查询后运行报告需要更长的时间。

我相信通过放弃 SELECT 语句中的子查询并使用连接来代替,查询/报告的性能可能会得到提高,但我目前对 SQL 很生疏,无法让它工作。

任何人都可以建议改进此查询以提高性能吗?

SELECT 
       transaction_type, 
       description,
       id_num,
       product_id,
       quantity,
       location_id,
       CASE WHEN transaction_log.location_id IS NOT NULL
            THEN ( SELECT TOP 1
                          master_location_id 
                     FROM location_table t1 
                    WHERE t1.location_id = transaction_log.source_location_id
                      AND master_location_id IS NOT NULL
                 )
            ELSE NULL
       END as master_location,
       dummy_value, 
       employee_id,
 FROM 
      transaction_log WITH (NOLOCK)

我尝试了如下的连接,它返回了 2000 多行(与上面的查询相比)。我是否应该在 WHERE 子句中进一步过滤结果?

SELECT 
       transaction_type, 
       description,
       id_num,
       product_id,
       quantity,
       location_id,
       master_location_id,
       dummy_value, 
       employee_id,
  FROM 
        transaction_log  t1 WITH (NOLOCK)
        INNER JOIN ( SELECT location_id,
                            master_location_id 
                       FROM location_table)  t2
                ON t1.location_id = t2.location_id
sql performance join optimization subquery
1个回答
0
投票

情况

  • transaction_log.location_id
    有时可能是
    NULL
    ,因此您需要确保获得具有
    NULL
    位置的事务日志条目。这意味着您需要一个外部联接。
  • location_table.master_location_id
    始终彼此相同或
    NULL
    ,因此您需要缩小此列表的范围,以便每个
    location_id
    master_location_id
    组合只有一行。
  • 让情况变得更加复杂的是,
    master_location_id
    有时可能是
    NULL
    ,因此,在缩小列表范围时,您需要去掉
    NULL
    值。正如下面的注释中所述,所有这些都可以拔出。

一个解决方案

SELECT 
       T_LOG.transaction_type, 
       T_LOG.description,
       T_LOG.id_num,
       T_LOG.product_id,
       T_LOG.quantity,
       T_LOG.location_id,
       U_LOC.master_location_id,
       T_LOG.dummy_value, 
       T_LOG.employee_id,
  FROM 
       transaction_log  T_LOG  WITH (NOLOCK)
       LEFT OUTER JOIN (
                           SELECT T_LOC.location_id,
                                  T_LOC.master_location_id 
                             FROM location_table  T_LOC
                            WHERE T_LOC.master_location_id IS NOT NULL
                         GROUP BY T_LOC.location_id,
                                  T_LOC.master_location_id
                       )  U_LOC
                    ON T_LOG.location_id = U_LOC.location_id
;

注意: 请考虑下表中的

location_table
值:


+-------------+--------------------+
| location_id | master_location_id |
+-------------+--------------------+
|          10 | 3                  |
|          10 | 3                  |
|          20 | NULL               |
|          30 | 7                  |
|          30 | NULL               |
+-------------+--------------------+

删除所有

NULL
master_location_id
行并按两列分组会产生以下效果:

+-------------+--------------------+
| location_id | master_location_id |
+-------------+--------------------+
|          10 |                  3 |
|          30 |                  7 |
+-------------+--------------------+

location_id
为 20 的行明显丢失。但是,如果该值在那里,
master_location_id
将是
NULL
。由于它不存在,因此
LEFT OUTER JOIN
无论如何都会为其返回
NULL
值。所以没有问题。

只有当您想要以不同于

location_table
中的
NULL
值的方式解释
location_table.master_location_id
中缺失的行时,才会出现问题。这超出了这个问题的范围。

© www.soinside.com 2019 - 2024. All rights reserved.