我的数据库中有一个记录表,其中有大约一百万条记录。大多数记录都是公开的 - 这意味着系统上的所有用户都可以查看它们。但是在同一张桌子上,我也有私人记录,每个用户通常有几百个。我在系统上有大约1K用户。
每条记录有3个主要栏目:
ID
- 记录ID的枚举。唯一的主键。UserID
- 标识记录所有者。 Null =每个人都可以使用的通用记录。 ID =仅适用于此特定用户ID的专用记录。RecID
- 公共记录ID。所有公共记录都是唯一的。如果用户更改了公共记录,系统会使用新ID复制此记录,但RecID
。实施例
ID RecID UserID Comments
----------------------------------------------------------------------------
1 1000 NULL General record
2 1000 1 Modification of record ID=1, available only for userID=1
3 1001 NULL General Record
4 1002 NULL General Record
5 1001 2 Modification of record ID=3, available only for userID=2
我使用的查询如下:
SELECT *
FROM TB_Records
WHERE UserID = @UserID
OR (RecID IS NULL AND NOT RecID IN (SELECT RecID
FROM TB_Records
WHERE UserID = @UserID)
我遇到的问题是性能问题。在此查询的基础上添加排序过滤和分页结果,每个选择的性能为5-10秒。删除查询的第3行 - 选择所有记录时,性能要好得多,1-2秒。
我想知道是否有更好的方法来处理这样的要求。
由于
答案 0 :(得分:1)
此查询没有意义。 AND NOT
部分是不必要的,因为NULL
RecID
值不会达到预期效果。我想你的意思是:
SELECT r.*
FROM TB_Records r
WHERE r.UserID = @UserID OR
(r.UserId IS NULL AND NOT r.RecID IN (SELECT r2.RecID
FROM TB_Records r2
WHERE r2.UserID = @UserID)
首先,在TB_Records(UserId, RecId)
上创建索引。这可能有所帮助。接下来,我会尝试将其更改为明确的left outer join
:
select r.*
from TB_Records r left outer join
TB_Records r2
on r2.UserId = @UserId and
r2.RecId = r.RecId
where r.UserId = @UserId or r2.RecId is NULL;
编辑:
使用不同的方法再尝试一次。这使用窗口函数来查看用户是否存在给定记录:
select r.*
from (select r.*,
max(case when r.UserId = @UserId then 1 else 0 end) over (partition by RecId) as HasUser
from TB_Records r
) t
where r.UserId = @UserId or HasUser = 0;
否则,您应该将执行计划放在问题中。有时,使用union all
的查询优于or
的查询:
select r.*
from TB_Records r
where r.UserId = @UserId
union all
select r.*
from TB_Records r left outer join
TB_Records r2
on r2.UserId = @UserId and
r2.RecId = r.RecId
where r2.RecId is NULL;