我有一个案例,我想选择任何无效的国家,地区或区域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
)
现在,我的查询是对的吗?你有什么建议我能做到并以更好的表现达到同样的效果?!
答案 0 :(得分: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行,并在找到该行时跳转到下一个迭代(即如果找不到给定Property的Country
,则它甚至不会检查对于Region
)。
同样,SQL Server
足够聪明,可以为此查询和原始查询构建相同的计划。
<强>更新强>
在每个表中的512K
行上进行测试。
维度表中的所有对应ID
都是CLUSTERED PRIMARY KEY
个,Properties
中的所有度量字段都已编入索引。
对于Property
中的每一行PropertyID = CountryID = RegionID = AreaID
,没有实际丢失的行(执行时间最差的情况)。
NOT EXISTS 00:11 (11 seconds) LEFT JOIN 01:08 (68 seconds)
答案 1 :(得分: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来加快速度 - 在每个主表(国家,地区,区域)中它们应该是群集主键。
答案 2 :(得分:3)
由于这似乎是清理sql,这应该没问题。但是如何使用foreign keys以便下次不打扰你?
答案 3 :(得分: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)
答案 4 :(得分: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
答案 5 :(得分: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)
这通常暗示使用countries等人的pkey索引进行存在检查......但是否这是一项改进取决于您的数据统计数据,您只需将其插入查询分析器并尝试它。