【问题标题】:Performance hit from simple change to query对查询的简单更改会影响性能
【发布时间】:2015-04-09 04:53:11
【问题描述】:

我曾经有一个简单的查询,按名称和日期连接 2 个表。

表 A:

Name    Date       Field1    Field2    Field3    ....
Abc     05-Apr-15  ...       ...       ...       ...

表 B:

Name    Date       Field1    Field2    ....
Abc     01-Apr-15  ...       ...       ...

查询:

select a.*, b.*
from tableA a
outer apply
  (select top 1 *
   from tableB b
   where b.name = a.name
   and b.date < a.date) x

此查询大约需要 1 秒才能运行。

由于2个表中的名称字段存在差异,我创建了一个参考表来标准化名称。所以我构建了一个如下查询:

select a.*, b.*
from tableA a
left join refFile ref
  on a.name = ref.aName
outer apply
  (select top 1 *
   from tableB b
   left join refFile ref
    on b.name = ref.bName
   where isnull(ref.stdName, b.name) = isnull(ref.stdName, a.name)
   and b.date < a.date) x

现在这个新查询大约需要 5 分钟才能完成。

我想知道有没有更有效的方法?

谢谢!

【问题讨论】:

  • 没有任何细节我会说问题是“isnull(ref.stdName, b.name) = isnull(ref.stdName, a.name)”,因为它不能使用任何索引,因为你在特别行政区有职能。也许您可以修复/将正确的名称添加到表中?
  • 我们需要查看执行计划,但正如 James 所说,第一次尝试是避免在 WHERE 子句中使用函数。
  • 尝试将 where 子句更改为:ref.stdName = a.name or ref.stdName = b.name or a.name = b.name。阅读this了解更多信息
  • 当您在 where 子句中使用函数时,在这种情况下为 IsNull,查询会降级。尝试通过“不为空”检查添加“和”条件

标签: sql sql-server performance tsql


【解决方案1】:

没有其他人提到的执行计划很难说,但在这里试试这个:

select a.*, b.*
from tableA a
left join refFile ref
  on a.name = ref.aName
outer apply
  (select top 1 *
   from tableB b
   left join refFile ref
    on b.name = ref.bName
   --It's not recommended to use functions in the where clause
   --because it wont use your indexes
   --where isnull(ref.stdName, b.name) = isnull(ref.stdName, a.name)

   --try this instead.
   WHERE (ref.stdName IS NULL AND A.Name = B.name)
   OR (ref.stdName IS NOT NULL)
   AND b.date < a.date) x

还有,为什么你有没有 ORDER BY 的 TOP?建议将它们一起使用以确保结果一致。

【讨论】:

  • 精湛的 Stephan,这是 where 子句中 isnull 函数的良好替代品。我欣赏逻辑思维。无论如何我们必须检查这个查询的执行计划来确认。
【解决方案2】:

我假设您的 refFile 表如下所示:

create table refFile
( stdName varchar primary key
, aName   varchar 
, bName   varchar
)

第 1 部分。看起来不错

select a.*, b.*
from tableA a
left join refFile ref on a.name = ref.aName

第 2 部分。你又加入refFile,为什么?除了b.date &lt; a.date 之外,与您的查询的第 1 部分没有任何关系。最重要的是,在该部分之外没有表 b,这意味着您在第 1 部分中的 b.* 无法工作。

outer apply (
  select top 1 *
    from tableB b
    left join refFile ref
    on b.name = ref.bName
   where isnull(ref.stdName, b.name) = isnull(ref.stdName, a.name)
   and b.date < a.date) x

建议第 2 部分:

outer apply (
  select top 1 b.*
    from tableB b 
    where B.name in (ref.bName, ref.stdName)
      and b.date < a.date
    order by b.date desc
) b

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多