Оптимизация запросов/базы данных:Как это оптимизировать?(и следует ли мне использовать материализованное представление?)

StackOverflow https://stackoverflow.com/questions/1496687

Вопрос

У меня вопрос о том, как оптимизировать запрос.На самом деле, поскольку я собираюсь часто выполнять запрос, я подумывал об использовании материализованного или индексированного представления (хорошая ли это идея здесь?) или денормализации.

Рассмотрим следующие четыре таблицы (без ненужных полей):

  • Пользователи (int userId)
  • Группы (int groupId)
  • GroupMemberships (int userId, int groupId, bool isSharing)
  • Компьютеры (int userId)

Отношения таковы, что пользователь может иметь 0..n компьютеров (один пользователь на множество компьютеров) и может быть членом 0..n групп.В группе может быть от 0 до n пользователей (много пользователей во многих группах).«isSharing» обозначает, предоставляет ли пользователь общий доступ к этой группе или является членом этой группы «только для чтения» (то есть может видеть компьютеры участников совместного доступа, но не предоставляет общий доступ к своим собственным).

Запрос состоит в том, чтобы найти для данного пользователя, какие компьютеры этот пользователь может видеть.Пользователь может видеть все свои компьютеры.Она также может видеть любые компьютеры других пользователей, которые входят в группы, членом которых она является, и делятся с этой группой.Хорошо, это не имеет особого смысла, поэтому вот цель псевдокода O(n^3):

List<Computer> l
foreach(Computer c in Computers)
    if(c.userId == current_user_id)
        add c to l
    else
        foreach(GroupMembership m where m.userId == current_user_id)
            foreach(GroupMembership m2 where c.userId == m2.userId && m.groupId == m2.groupId)
                if(m2.isSharing)
                    add c to l

Прямо сейчас я использую сопоставитель ORM и в основном делаю все вышеперечисленное (я не слишком хорошо разбираюсь в SQL), но это, очевидно, далеко не идеальное решение.У меня есть индексы для каждого поля, которое я там перечислил (кроме isShared), и дополнительный индекс для кортежа GroupMembership (userId, groupId).Но могут ли мастера баз данных придумать лучшее решение?

Проект еще не запущен, но я предполагаю, что в среднем будет 1,2 компьютера на одного пользователя (у каждого будет один, у некоторых может быть больше) и, возможно, 0,75 членства в группах на пользователя (многие пользователи не будут использовать группы). функция, но те, кто это сделает, скорее всего, будут членами нескольких групп).Кроме того, все эти связанные таблицы будут часто дополняться, что может сделать материализованные представления менее практичным решением.Я использую SQL Server 2008.

Спасибо, Всего наилучшего, Роберт

Это было полезно?

Решение

Я думаю, что это будет сделано без каких-либо подзапросов.Отказ от ответственности:Это из головы, не проверялось.

select distinct computerId
from groupMemberships m1
join groupMemberships m2 on m2.groupId=m1.groupId
  and (m2.isSharing or m2.userId=m1.userId)
join computers c on c.userId=m2.userId
where m1.userId=?

Нет необходимости читать таблицы группы пользователей, если из этих таблиц нет других данных, которые вы хотите включить в выборку, которые вы не упомянули.

«isSharing или userId» должен предоставить вам ваши собственные компьютеры, а также любые общие компьютеры.Это может быть излишне умно:простой союз может быть более эффективным.

Другие советы

Хорошо, я так понимаю, вам нужны таблица и запросы для указанной выше спецификации?

Я из спецификации взял, что компьютер "прикреплен" к данному пользователю, а можно поделиться?

Компьютеры (int userId)

Посмотрите на это и дайте мне знать, если вы хотите изменить какие-либо характеристики.

DECLARE @Users TABLE(
        UserID INT
)

DECLARE @Computers TABLE(
        ComputerID INT,
        UserID INT
)

DECLARE @Groups TABLE(
        GroupID INT
)

DECLARE @GroupMemberships TABLE(
        UserID INT,
        GroupID INT,
        IsSharing INT
)

INSERT INTO @Users (UserID) SELECT 1
INSERT INTO @Users (UserID) SELECT 2

INSERT INTO @Computers (ComputerID, UserID) SELECT 1, 1
INSERT INTO @Computers (ComputerID, UserID) SELECT 2, 1
INSERT INTO @Computers (ComputerID, UserID) SELECT 3, 1
INSERT INTO @Computers (ComputerID, UserID) SELECT 4, 2
INSERT INTO @Computers (ComputerID, UserID) SELECT 5, 2

INSERT INTO @Groups (GroupID) SELECT 1
INSERT INTO @Groups (GroupID) SELECT 2
INSERT INTO @Groups (GroupID) SELECT 3

INSERT INTO @GroupMemberships (UserID,GroupID,IsSharing) SELECT 1, 1, 0
INSERT INTO @GroupMemberships (UserID,GroupID,IsSharing) SELECT 1, 2, 1
INSERT INTO @GroupMemberships (UserID,GroupID,IsSharing) SELECT 2, 2, 0
INSERT INTO @GroupMemberships (UserID,GroupID,IsSharing) SELECT 2, 3, 0

DECLARE @UserID INT
--SELECT @UserID = 1
SELECT @UserID = 2

SELECT  DISTINCT 
        ComputerID
FROM    @Computers
WHERE   UserID = @UserID
UNION
SELECT  DISTINCT 
        ComputerID
FROM    @Computers c INNER JOIN
        (
            SELECT  DISTINCT 
                    gm.UserID
            FROM    @GroupMemberships gm INNER JOIN
                    @GroupMemberships ThisUserGroups    ON  gm.GroupID = ThisUserGroups.GroupID
                                                        AND ThisUserGroups.UserID = @UserID
            WHERE   gm.UserID != @UserID
            AND             gm.IsSharing = 1
    ) OtherUsersInSharedGroups ON c.UserID = OtherUsersInSharedGroups.UserID
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top