【问题标题】:SQLServer query using memory innefficientlySQL Server 查询有效地使用内存
【发布时间】:2016-01-18 19:07:20
【问题描述】:

我在 Sql Server 中开发了一个插入语句。它利用了几个连接和一个内部选择。由于内存不足,它导致我的数据库出现问题。

尽管只插入了几百行,它也需要几分钟才能运行。是否有人对我如何改进此查询以使其在不更改最终结果的情况下更有效地运行有建议?谢谢!

insert into This_Table 
select distinct *
from fv
join lv on lv.field1 = fv.field1
join sa on sa.field1 = fv.field2
where field3 + field2 not in (select distinct field3 + field2
from fv
join lv on lv.field1 = fv.field1
join This_Table T on fv.field2 COLLATE SQL_Latin1_General_CP1_CI_AS + case 
when COMPONENT_PART COLLATE SQL_Latin1_General_CP1_CI_AS like 'S%' or `COMPONENT_PART COLLATE SQL_Latin1_General_CP1_CI_AS like 'T%' then STUFF(field3 COLLATE SQL_Latin1_General_CP1_CI_AS, 1, 1, '') else COMPONENT_PART COLLATE     SQL_Latin1_General_CP1_CI_AS end like T.field4 + case when field5 like 'S%' or     field5 like 'T%' then STUFF(field5, 1, 1, '') else T.field5 end + '%')`
and SA.field6 <> 'EXPIRED'
order by field3

【问题讨论】:

  • 这只是我的观察,更改 distinct > GROUP BY,将 'NOT IN' > 更改为左连接,所有 'WHERE' 条件都在 JOIN 处使用它...如果你扔桌子架构和数据示例有人可能会帮助您
  • 带有插入的ORDER BY 是多余的,因为表中的数据没有排序。 NOT IN 子句中的 DISTINCT 也是多余的,可能会导致 DBMS 做不必要的工作。那么如何使用DISTINCT 删除重复记录?来自三个表的select *;其中之一是否包含重复记录?如果是这样,为什么?如果不是这样,为什么DISTINCT
  • 您加入列表达式 (fv.field2 + case when ... end like T.field4 + case when ... end) 而不仅仅是列,这很可能表明数据库模型不好。
  • @Veljko89: No. (1.) GROUP BY 用于数据聚合(SUMCOUNT 等)。如果您只想要不同的行,请使用直接的DISTINCT,以便尽可能少地给 DBMS 工作。 (2.) 反连接模式是一种用于不知道如何有效处理[NOT] IN/[NOT] EXISTS 的弱 DBMS 的技巧。我怀疑当前版本的 SQL Server 会那么弱。 (3.) 在ONWHERE 中是否有内部联接标准不会影响性能。这只是可读性的问题。但是,是的,(4) 表定义和示例数据可能会有所帮助:-)
  • 您可能会在SO's dba site 上找到更多帮助。在询问查询性能时,如果包含执行计划总是有帮助的。

标签: sql sql-server optimization insert query-optimization


【解决方案1】:

这里的赠品是您的查询中有一个DISTINCT。我无法从您提供的信息中知道它是否适用于此,但在 99% 的情况下,我看到了 DISTINCT,它被用来“修复”不完整的JOINs。

其他一些注意事项:

  • 添加别名,尤其是在同一个查询中多次使用同一张表时;这使事情更具可读性
  • 您可以使用LIKE '[AB]%' 代替LIKE 'A%' OR LIKE 'B%'
  • 单独比较field3field2 可能比比较它们的总和 更有趣。
  • 尽量使“过滤器”尽可能接近其表定义。在这种情况下,我建议将sa.field6 &lt;&gt; 'EXPIRED' 放在JOIN sa 子句旁边。这是可选的,但如果您需要OUTER JOIN,它会突然变成必需品!
  • 我也有点担心这里发生的所有整理魔法……但也许您的数据需要它……

不管怎样,重写你的代码,我来了:

INSERT INTO This_Table 
SELECT DISTINCT * -- need ALL fields? Even then, better specify them explicitly!
  FROM fv
  JOIN lv 
    ON lv.field1 = fv.field1
  JOIN sa 
    ON sa.field1 = fv.field2
   AND sa.field6 <> 'EXPIRED'
 WHERE NOT EXISTS ( SELECT *
                    FROM fv fv22
                    JOIN lv lv2 
                      ON lv2.field1 = fv2.field1
                    JOIN This_Table T 
                      ON fv2.field2 COLLATE SQL_Latin1_General_CP1_CI_AS 
                                + (CASE WHEN COMPONENT_PART COLLATE SQL_Latin1_General_CP1_CI_AS LIKE '[ST]%' 
                                            THEN STUFF(field3 COLLATE SQL_Latin1_General_CP1_CI_AS, 1, 1, '')             
                                            ELSE COMPONENT_PART COLLATE SQL_Latin1_General_CP1_CI_AS END) 
                               LIKE T.field4 + (CASE WHEN field5 LIKE '[ST]%' 
                                                        THEN STUFF(field5, 1, 1, '') 
                                                        ELSE T.field5 END + '%')

                   WHERE fv2.field2 = fv.field2 -- not quite the same as what you had but I'm guessing this is what you wanted
                     AND fv2.field3 = fv.field3 )

回想起来,假设我没有搞砸,我现在想知道你是否真的需要加入到 lv 的第一时间?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    相关资源
    最近更新 更多