【问题标题】:comparison query taking ages比较查询耗时
【发布时间】:2012-04-06 08:17:33
【问题描述】:

我的查询很简单:

select  a.ID, a.adres, a.place, a.postalcode  
from COMPANIES a, COMPANIES b  
where a.Postcode = b.Postcode  
and a.Adres = b.Adres  
and (  
select COUNT(COMPANYID)  
from USERS  
where COMPANYID=a.ID  
)>(  
select COUNT(COMPANYID)  
from USERS  
where COMPANYID=b.ID  
)

数据库:sql server 2008 r2

我正在尝试做的事情: COMPANIES 表包含双重条目。我想知道连接到最多用户的那些。所以我只需要更改那些最少的外键。 (我已经知道双打的ID了)

现在需要很长时间才能完成。我想知道是否可以更快地完成

【问题讨论】:

  • 您是否在连接和 where 子句列上定义了索引?
  • 是的,ID 是公司的主键,companyid 被索引,因为我们经常使用连接来搜索用户。
  • 还有 PostcodeAdres 字段的自联接?
  • 邮政编码是 (nvarchar) adres no (nvarchar)
  • 这可能是您查询缓慢的原因。顺便说一句,您应该使用正确的 JOIN 子句,而不是与 WHERE 交叉连接(更多的是风格问题而不是性能问题)。

标签: sql tsql comparison sql-server-2008-r2


【解决方案1】:

试试这个版本。它应该只是快一点。 COUNT 很慢。我已经添加了a.ID <> b.ID 以避免之前出现少数情况。

select  a.ID, a.adres, a.place, a.postalcode  
from COMPANIES a INNER JOIN COMPANIES b
ON
a.ID <> b.ID
and a.Postcode = b.Postcode  
and a.Adres = b.Adres  
and (  
select COUNT(COMPANYID)  
from USERS  
where COMPANYID=a.ID  
)>(  
select COUNT(COMPANYID)  
from USERS  
where COMPANYID=b.ID  
)

FROM ... INNER JOIN ... ON ... 是连接表的首选 SQL 构造。它也可能更快。

【讨论】:

  • 快一点?我的测试集时间从 2 分钟缩短到 9 秒。节省 92.5%。现在在完整版上测试它。只是通知您:您在 b.IDa.postcode 之间缺少一个 and
  • @WouterVerleur 添加“a.ID b.ID”会导致丢弃自我匹配,从而减少计数。
  • 根据@NikolaMarkovinović,它的 ID 检查加快了查询速度,但我会重申使用内连接的建议......而不是在哪里 - 它使您的查询更清晰( where 子句是关于过滤数据的,并且表之间的连接是分开的)
【解决方案2】:

一种方法是在执行连接之前预先计算COMPANYID 计数,因为您将在主查询中重复计算它。即类似:

insert into @CompanyCount (ID, IDCount)
select COMPANYID, COUNT(COMPANYID)
from USERS
group by COMPANYID

然后你的主要查询:

select a.ID, a.adres, a.place, a.postalcode
from COMPANIES a
  inner join @CompanyCount aCount on aCount.ID = a.ID
  inner join COMPANIES b on b.Postcode = a.Postcode and b.Adres = a.Adres
  inner join @CompanyCount bCount on bCount.ID = b.ID and aCount.IDCount > bCount.IDCount

如果您想要a 的所有实例,即使没有对应的b,那么您需要left outer joins 到bbCount

但是您需要查看查询计划 - 您正在使用哪些索引 - 您可能希望至少将它们放在 IDs 和 PostcodeAdres 字段中,因为您正在加入他们。

【讨论】:

  • 试过:只给了我 2 行,而原版给了我 34 行,但似乎什么都没有。我只想比较 a 对应的 b(只有双打)。
  • 由于@Michas 为您提供了一个有效的答案(我已赞成),我不会继续这样做 - 我可能需要有关您的数据的更多信息 - 这是在没有我测试的情况下编写的,它在理论上有效 :-) 我建议的一件事是避免使用名为“ID”的列 - 如果它们像您的 CompanyID 一样具体,它可以减少查询中的混淆
  • 说实话,我尽量避免使用少于 5 个字符的字段名。但我不是创建数据库的人。早在 2000 年就创建了数据库。我正在做的工作是迁移到一个新系统(使用我设计的全新数据库)。感谢您的建议。我会记住的。
【解决方案3】:
  1. 建立关于邮政编码和地址的索引

  2. 数据库可能会为每一行执行子选择。 (只是在这里猜测,在解释计划中对其进行验证。如果是这种情况,您可以重写查询以加入内联视图(注意这是它在 oracle hop 中的外观,它也适用于 sql server):

    select distinct a.ID, a.adres, a.place, a.postalcode  
    from 
        COMPANIES a, 
        COMPANIES b,  
    (
        select COUNT(COMPANYID) cnt, companyid  
        from USERS
        group by companyid) cntA,  
    (
        select COUNT(COMPANYID) cnt, companyid  
        from USERS
        group by companyid) cntb   
    where a.Postcode = b.Postcode  
    and a.Adres = b.Adres  
    and a.ID<>b.ID
    and cnta.cnt>cntb.cnt
    

【讨论】:

  • 这在 SQL 结果中不起作用:Msg 8120, Level 16, State 1, Line 6 Column 'USERS.COMPANYID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
  • 抱歉,错过了分组。添加它。可能仍然包含一个或多个拼写错误.. 没有在数据库上尝试过
  • 我要到周二才能测试它,但我会看看它是否有效。说不定我们俩都能从中吸取教训吧?
  • 这个也可以,但是在选择和之后错过了:` distinct`。 a.ID&lt;&gt;b.ID and 在哪里之后
猜你喜欢
  • 1970-01-01
  • 2017-06-21
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
相关资源
最近更新 更多