【问题标题】:Left outer join with left() function使用 left() 函数的左外连接
【发布时间】:2018-06-08 14:33:18
【问题描述】:

我每天(通宵)运行以下查询,运行需要相当长的时间(1-1.5 小时)。我确定“Acc.DateKey >= LEFT (LocationKey, 8)”是原因,如果删除这部分连接,查询将在大约 5 分钟内执行。我只是想不出更有效的方法。

Acc.DateKey 是一个 bigint,通常是 20180101 等,位置键是一个 bigint,通常是 201801011234 等。

到目前为止,我已经考虑在 LO 表“AccLocationKey”中包含一个新列,该列将在加载时与 LEFT (LocationKey, 8) 函数一起插入。

我决定先在这里提出问题 - 是否可以在不更改 LO 表的情况下对此进行改进?

SELECT
ISNULL(MAX(L.LocationKey),(SELECT MIN(LocationKey) FROM LO WHERE Location = Acc.Location)) AS LocationKey
FROM
Acc
LEFT OUTER JOIN
(
    SELECT
        LocationKey
        ,Location
    FROM
        LO
)AS L
ON Acc.Location = L.Location AND Acc.DateKey >= LEFT(LocationKey,8)

【问题讨论】:

  • 您能否提供一些关于表格大小等的虚拟数据和上下文?
  • 一般来说,您当然希望避免连接条件中的不等式和函数。你能发布表格 DDL 吗?你看过解释计划了吗?

标签: sql sql-server left-join


【解决方案1】:

让我们重写SELECT中没有子查询的查询:

SELECT COALESCE(MAX(L.LocationKey), MIN(L.MIN_LocationKey)) AS LocationKey
FROM Acc LEFT OUTER JOIN
     (SELECT MIN(l.LocationKey) OVER (PARTITION BY l.Location) as min_location,
             l.*
      FROM LO l
     ) L
     ON Acc.Location = L.Location AND Acc.DateKey >= LEFT(l.LocationKey, 8);

可能您获得性能的最佳机会是添加计算列和适当的索引。所以:

alter table lo add locationkey_datekey as (try_convert(bigint, LEFT(l.LocationKey, 8))) persisted;

然后,相应的索引:

create index idx_lo_location_datekey on lo(location, locationkey_datekey);

然后在查询中使用这个:

SELECT COALESCE(MAX(L.LocationKey), MIN(L.MIN_LocationKey)) AS LocationKey
FROM Acc LEFT OUTER JOIN
     (SELECT MIN(l.LocationKey) OVER (PARTITION BY l.Location) as min_location,
             l.*
      FROM LO l
     ) L
     ON Acc.Location = L.Location AND Acc.DateKey >= l.LocationKey_datekey;

幸运的是,这个索引也适用于窗口函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 2016-11-23
    相关资源
    最近更新 更多