2015-05-26 2 views
1

Я хотел бы спросить об одном конкретном представлении, которое у меня есть, и потенциальной оптимизации.Оптимизация представления с объединением/перекрестным соединением

Похоже, что довольно обычная установка таблиц - клиенты (~ 50 000 строк) и пользователи (~ 250 строк), в то время как большинство пользователей могут получить доступ ко всем клиентам (infact, есть другой уровень разрешений на географическое расположение клиентов, но он похоже, не подходит для этой проблемы, я напишу дополнительный вопрос ниже), есть определенные пользователи (с RoleId = 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] 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 здесь.

И еще один вопрос - идея пришла мне в голову:

  • Чтобы расширить это представление с другим разрешением на клиента географическое положение (M: N пользователя таблицы: расположение в то время как клиент всегда один местоположение) ,
  • В настоящее время я проверяю его дополнительно в нескольких родительских представлениях - будет ли это увеличить производительность родительских представлений в любом случае значительно?

Заранее спасибо

EDIT: Согласно Гордонс ответ, я попытался изменить мнение следующим образом, и это помогло.

Теперь я думаю немного больше об использовании этого представления - я имею в виду, что в этом случае (когда большинство пользователей могут получить доступ к клиенту) будет лучшим подходом к показу только ограниченным клиентам и спросите, есть ли у клиента и пользователь не находится в выбранном представлении? (приложение написано на C# .NET MVC выше SP 2010).

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 

ответ

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] 
+0

Спасибо, это то, о чем я думал в редактировании несколько секунд назад! – Zax

+0

Добро пожаловать, друг. –

1

Что ухудшает производительность в этом запросе не cross join, но union. Он имеет дополнительную логику для удаления дубликатов.

Try фразировка это немного по-другому:

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).

+0

У меня есть идея, но я предполагаю, что есть опечатка в избранных. Я сделал это, как при редактировании вопроса, и теперь oit работает намного гладко. Спасибо. – Zax

+0

@Zax. , , Псевдоним таблицы в подзапросе должен быть 'u2' (как сейчас). –

Смежные вопросы