1

我有一个案例,我想选择任何具有无效国家、地区或地区 ID 的数据库条目,无效,我的意思是我的表中不再存在的国家或地区或地区的 ID,我有四个表:属性、国家、地区、地区。我想这样做:

SELECT * FROM Properties WHERE 
Country_ID NOT IN 
(
SELECT CountryID FROM Countries
)
OR
RegionID NOT IN
(
SELECT RegionID FROM Regions
)
OR
AreaID NOT IN
(
SELECT AreaID FROM Areas
)

现在,我的查询对吗?你有什么建议我可以做,并以更好的性能达到相同的结果?!

4

6 回答 6

4

您的查询实际上是最佳的。

LEFT JOIN其他人提出的更糟糕,因为他们选择了所有值,然后将它们过滤掉。

很可能您的子查询将为此优化:

SELECT  *
FROM    Properties p
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    Countries i
        WHERE   i.CountryID = p.CountryID
        )
        OR
        NOT EXISTS
        (
        SELECT  1
        FROM    Regions i
        WHERE   i.RegionID = p.RegionID
        )
        OR
        NOT EXISTS
        (
        SELECT  1
        FROM    Areas i
        WHERE   i.AreaID = p.AreaID
        )

, 你应该使用它。

此查询从每个表中最多选择 1 行,并在找到该行时跳到下一次迭代(即,如果它没有找到Country给定属性的 a ,它甚至不会检查 a Region)。

同样,SQL Server它足够聪明,可以为此查询和您的原始查询构建相同的计划。

更新:

512K对每个表中的行进行测试。

维度表中所有对应ID的 ' 都是CLUSTERED PRIMARY KEY',所有度量字段Properties都被索引。

对于 , 中的每一行PropertyPropertyID = CountryID = RegionID = AreaID没有实际缺失的行(就执行时间而言最坏的情况)。

不存在 00:11(11 秒)
左加入 01:08(68 秒)
于 2009-04-14T11:51:25.537 回答
3

你可以用不同的方式重写它,如下所示:

SELECT p.* 
FROM Properties p
LEFT JOIN Countries c ON p.Country_ID = c.CountryID
LEFT JOIN Regions r on p.RegionID = r.RegionID
LEFT JOIN Areas a on p.AreaID = a.AreaID
WHERE c.CountryID IS NULL
OR r.RegionID IS NULL
OR a.AreaID IS NULL

测试性能差异(如果有的话 - 应该有,因为 NOT IN 是一个讨厌的搜索,特别是在很多项目上,因为它必须测试每一个项目)。

您还可以通过为正在搜索的 IDS 建立索引来加快速度——在每个主表(国家、地区、地区)中,它们应该是聚集的主键。

于 2009-04-14T11:43:06.447 回答
3

由于这似乎是清理sql,这应该没问题。但是如何使用外键以便下次不会打扰您呢?

于 2009-04-14T11:44:07.723 回答
1

好吧,您可以尝试UNION(而不是)之类的事情OR-但我希望优化器已经在提供可用信息的情况下尽其所能:

SELECT  * FROM  Properties
WHERE   NOT EXISTS (SELECT 1 FROM Areas WHERE Areas.AreaID = Properties.AreaID)
UNION
SELECT  * FROM  Properties
WHERE   NOT EXISTS (SELECT 1 FROM Regions WHERE Regions.RegionID = Properties.RegionID)
UNION
SELECT  * FROM  Properties
WHERE   NOT EXISTS (SELECT 1 FROM Countries WHERE Countries.CountryID = Properties.CountryID)
于 2009-04-14T11:44:36.677 回答
0

条件中的子查询可能非常低效。相反,您可以对相关表进行左连接。如果没有匹配的记录,您会得到一个空值。您可以在条件中使用它来仅选择缺少匹配记录的记录:

select p.*
from Properties p
left join Countries c on c.CountryID = p.Country_ID
left join Regions r on r.RegionID = p.RegionID
left join Areas a on a.AreaID = p.AreaID
where c.CountryID is null or r.RegionID is null or a.AreaID is null
于 2009-04-14T11:46:28.950 回答
0

如果您没有从国家/地区/地区获取行数据,您可以尝试使用“存在”:

SELECT Properties.*
FROM Properties
WHERE Properties.CountryID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM Countries WHERE Countries.CountryID = Properties.CountryID)
OR Properties.RegionID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM Regions WHERE Regions.RegionID = Properties.RegionID)
OR Properties.AreaID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM Areas WHERE Areas.AreaID = Properties.AreaID)

这通常会提示使用国家等的 pkey 索引进行存在检查......但这是否是一种改进取决于您的数据统计,您只需将其插入查询分析器并尝试它。

于 2009-04-14T11:52:17.467 回答