SQL Server T-SQL查询优化

时间:2011-10-25 09:56:27

标签: tsql

我有一个T-SQL查询,我想让它更快。

我有EntityAddress表,如果存在邮寄地址,希望带回地址。

有时任何给定实体都有多个地址。有一个主要邮件地址tinyint有时会设置,有时不会,这里没有规则可能有5个默认邮件地址所有标志设置或没有设置标志。

对于11k行,大约需要20秒,我真的需要把这个时间缩短,有人可以帮忙吗?

SELECT 
   e.*, addr.*
FROM 
   [Entity] e
   --Address does not always exist
   --PrimaryAddress is a Not Null TinyInt, sometimes this flag is enable twice for a given entity.
LEFT OUTER JOIN 
   [Address] addr ON addr.[EntityID] = e.[EntityID] 
   AND addr.Code = 'MAILING'        
   AND addr.[AddressID] = (
       --This remove duplicates but add's a long delay(15 seconds) to execution time.
       SELECT Top 1 a.[AddressID]
       FROM [Address] AS a
       WHERE a.Code = 'MAILING'
         AND a.[EntityID] = e.[EntityID]    
       ORDER BY a.[PrimaryAddress] DESC)

还应该注意,我不能向两个表添加任何索引:(

亲切的问候 西蒙杰克逊

3 个答案:

答案 0 :(得分:1)

这是您的查询的简化版本,我认为将返回相同的行。 (未经测试)。我不能说这会比你的版本更快。你告诉我。

SELECT 
    e.*,
    addr.*
FROM 
    [Entity] e
  OUTER APPLY (
                SELECT TOP(1) *
                FROM addr as a
                WHERE a.Code = 'MAILING'
                AND a.[EntityID] = e.[EntityID] 
                ORDER BY a.[PrimaryAddress] DESC
              ) as addr

答案 1 :(得分:1)

您可以停止使用select *,您将返回实体ID两次,这会浪费服务器和网络资源。你真的需要其他领域的每一个吗?消除任何你不需要的东西。无论如何,选择*不应该用在生产代码中。

你有一个相关的子查询,它通过痛苦的行来运行行,尝试使用联接:

SELECT     e.*, addr.* 
FROM     [Entity] e     
LEFT JOIN   (SELECT addr.* 
            FROM  [Address] a
            JOIN     
                (SELECT Top 1 a.[AddressID]        
                FROM [Address] AS a        
                WHERE a.Code = 'MAILING'          
                AND a.[EntityID] = e.[EntityID]            
                ORDER BY a.[PrimaryAddress] DESC) dedup
                    ON a.address_id = dedup.address_id) addr 
    ON addr.[EntityID] = e.[EntityID] 

再次不要使用select *,我不知道你的字段,或者我会在上面指定它们。

当然,解决这个问题的真正方法是修复设计糟糕的数据库。它不应该允许多个主地址(我们通过触发器强制执行此操作),然后您不需要昂贵的删除重复任务。我意识到在你的情况下这是不可能的,但它可能会让别人想到他们的设计缺陷。由于这是第三方产品,我会要求他们修复它只允许一个主要地址。最终,如果有足够的人抱怨,他们可能会。

答案 2 :(得分:0)

如果您使用的是SQL Server 2005或更高版本,则可以尝试以下操作:

WITH ranked AS (
  SELECT
    *,
    rn = ROW_NUMBER() OVER (PARTITION BY EntityID ORDER BY [PrimaryAddress] DESC)
  FROM [Address]
  WHERE Code = 'MAILING'
)
SELECT
  e.*, a.*
FROM [Entity] e
  LEFT JOIN [Address] a ON a.[EntityID] = e.[EntityID] AND a.rn = 1

此查询的结果与您的查询结果略有不同:rn还有一列1和/或NULL s。我不认为这是一个问题,因为首先不建议在生产查询中使用屏蔽的SELECT列表,如果这是一个非生产脚本,那么一个额外的列几乎不会妨碍。

参考文献: