在SQL查询中设置差异

时间:2010-04-01 05:26:34

标签: sql-server tsql query-optimization

我正在尝试用语句选择记录

SELECT * 
FROM A 
WHERE 
  LEFT(B, 5) IN 
    (SELECT * FROM 
       (SELECT LEFT(A.B,5), COUNT(DISTINCT A.C) c_count 
        FROM A 
        GROUP BY LEFT(B,5)
       ) p1 
       WHERE p1.c_count = 1
     ) 
     AND C IN 
        (SELECT * FROM 
            (SELECT A.C , COUNT(DISTINCT LEFT(A.B,5)) b_count 
             FROM A 
             GROUP BY C
            ) p2 
          WHERE p2.b_count = 1)

需要很长时间才能运行~15秒。

有没有更好的方法来编写这个SQL?

4 个答案:

答案 0 :(得分:1)

如果您想在SQL中表示Set Difference(A-B),这里有适合您的解决方案。 假设您有两个表A和B,并且您想要检索仅存在于A但不存在于B中的所有记录,其中A和B通过名为ID的属性具有关系。 对此的有效查询是:

# (A-B)
SELECT DISTINCT A.* FROM (A LEFT OUTER JOIN B on A.ID=B.ID) WHERE B.ID IS NULL

- 来自Jayaram Timsina的博客。

答案 1 :(得分:0)

嗯,不确定你在这里真正想做什么 - 但显然,LEFT(B, 5)表达式不断涌现。由于您正在使用某个函数,因此您放弃了使用索引的任何机会。

您可以在SQL Server表中执行的操作是为该表达式创建计算的持久列,然后在其上添加索引:

ALTER TABLE A
   ADD LeftB5 AS LEFT(B, 5) PERSISTED

CREATE NONCLUSTERED INDEX IX_LeftB5 ON dbo.A(LeftB5)

现在在您的查询中的任何位置使用新的计算列LeftB5而不是LEFT(B, 5) - 这应该有助于加快某些查找和GROUP BY操作。

此外 - 你有一个GROUP BY C - C列索引了吗?

答案 2 :(得分:0)

您不需要从嵌套子查询返回数据。我不确定这会对iut索引产生影响,但它更容易阅读。

EXISTS / JOIN可能更好,然后使用IN

SELECT * 
FROM
    A 
    JOIN
    (SELECT LEFT(B,5) AS b1
        FROM A 
        GROUP BY LEFT(B,5)
        HAVING COUNT(DISTINCT C) = 1
    ) t1 On LEFT(A.B, 5) = t1.b1
    JOIN
    (SELECT C AS C1
        FROM A 
        GROUP BY C
        HAVING COUNT(DISTINCT LEFT(B,5)) = 1
    ) t2 ON A.C = t2.c1

但是你需要一个计算列,因为marc_s至少说过

还有2个索引:一个在(computed, C)上,另一个在(C, computed)

答案 3 :(得分:0)

如果您只是在寻找table1table2之间的差异, 下面的查询很简单,它给出了table1中的行,但没有给出table2中的行,因此两个表都是相同模式的实例,其列名与 columnonecolumntwo,...

with 
col1 as (
  select columnone from table2
  ),
col2 as (
  select columntwo from table2
)
...
select * from table1
where (
  columnone not in col1 
  and columntwo not in col2
  ...
);