我有一个T-SQL查询,我想让它更快。
我有Entity
和Address
表,如果存在邮寄地址,希望带回地址。
有时任何给定实体都有多个地址。有一个主要邮件地址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)
还应该注意,我不能向两个表添加任何索引:(
亲切的问候 西蒙杰克逊
答案 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列表,如果这是一个非生产脚本,那么一个额外的列几乎不会妨碍。
参考文献: