我想问一下我的一个具体观点和潜在的优化。
看起来像一个非常随意的表设置 - 客户(约50.000行)和用户(约250行),而大多数用户可以访问所有客户(事实上,客户的地理位置有不同的权限级别,但它确实似乎与此问题无关,我将在下面发布其他问题),有一些用户(使用RoleId = 1)只能访问他们自己的客户。 我以前的一个coleague做了一个数据库视图来评估某个用户是否可以访问某个客户。
以下是视图定义。
CREATE VIEW [dbo].[ViewUserAllowedCustomer]
AS
SELECT
u.[Id] UserId
, c.[Id] CustomerId
FROM [dbo].[User] u
CROSS JOIN [dbo].[Customer] c
WHERE
u.[RoleId] NOT IN (1) --Specific role for which the below part is required
UNION
SELECT
u.[Id] UserId
, c.[Id] CustomerId
FROM [dbo].[User] u
JOIN [dbo].[Customer] c ON u.[EmployeeId] = c.[EmployeeId]
现在我正在寻找一种更好的方法来定义这个视图并可能删除union join or cross join
或甚至会损害性能?
我想知道是否有任何最佳实践或完全不同于一个在这里使用。至少我要在这里添加UNION ALL
而不是UNION
。
另外一个问题 - 我想到了一个想法:
提前致谢
修改 根据Gordons的回答,我尝试按如下方式修改视图,并且它有很多帮助。
现在我正在考虑使用这个视图 - 我的意思是,在这种情况下(当大多数用户可以访问客户时)是一种更好的方法,只显示受限制的客户并询问客户和用户不在选定的视图中? (app是用SP 2010上面的C#.NET MVC编写的。)
SELECT u.[Id] as UserId, c.[Id] as CustomerId
FROM [dbo].[User] u JOIN
[dbo].[Customer] c
ON u.[EmployeeId] = c.[EmployeeId]
UNION ALL
SELECT u.[Id] as UserId, c.[Id] as CustomerId
FROM [dbo].[User] u CROSS JOIN
[dbo].[Customer] c
WHERE NOT EXISTS (SELECT 1 FROM dbo.[User] u2 WHERE u2.Id = u.Id AND u.RoleId = 1) --this here might be changed for a casual != rule on RoleId, but this describes the original idea, which I think is pretty good
答案 0 :(得分:1)
此查询的性能损害不是cross join
,而是union
。它有额外的逻辑来删除重复。
尝试稍微改写一下:
SELECT u.[Id] as UserId, c.[Id] as CustomerId
FROM [dbo].[User] u JOIN
[dbo].[Customer] c
ON u.[EmployeeId] = c.[EmployeeId]
UNION ALL
SELECT u.ID as UserId, c.ID as CustomerId
FROM [dbo].[User] u JOIN
[dbo].[Customer] c
ON u.[EmployeeId] = c.[EmployeeId]
WHERE NOT EXISTS (SELECT 1 FROM dbo.[User] u2 WHERE u2.EmployeeId = u.EmployeeId AND u.RoleId = 1);
您需要User(EmployeeId, RoleId)
上的索引。
答案 1 :(得分:1)
尝试使用查询获得更好的性能:
CREATE VIEW [dbo].[ViewUserAllowedCustomer]
AS
SELECT
u.[Id] UserId
, c.[Id] CustomerId
FROM [dbo].[User] u
CROSS JOIN [dbo].[Customer] c
WHERE
u.[RoleId] != 1 --Specific role for which the below part is required
UNION ALL
SELECT
u.[Id] UserId
, c.[Id] CustomerId
FROM [dbo].[User] u
JOIN [dbo].[Customer] c ON u.[EmployeeId] = c.[EmployeeId]
WHERE u.[RoleId] = 1
新想法(删除uniun):
它接缝你试图有一个可以与用户访问的客户白名单
如果是这样,我会建议有一个用户无法访问的客户黑名单
这样的事情可能有所帮助:
CREATE VIEW [dbo].[ViewUserNotAllowedCustomer]
AS
SELECT
u.[Id] UserId
, c.[Id] CustomerId
FROM [dbo].[User] u
CROSS JOIN [dbo].[Customer] c
WHERE
u.[RoleId] = 1 AND u.[EmployeeId] != c.[EmployeeId]