0

我有一個關於如何優化查詢的問題。實際上,由於我會頻繁地運行查詢,因此我正在考慮使用物化或索引視圖(這是個好主意嗎?)還是反規範化。查詢/數據庫優化:如何優化? (我應該使用物化視圖?)

考慮以下四個表(省略不相關的字段):

  • 用戶(INT用戶id)
  • 組(INT的groupId)
  • GroupMemberships(INT用戶id,整數的groupId,布爾isSharing)
  • 計算機(INT用戶id)

的關係是,一個用戶可以有0..n的計算機(一個用戶到人y計算機)並且可以是0..n組的成員。一個組可以有0..n個用戶(許多用戶到很多組)。 「isSharing」表示用戶是共享該組還是該組的「只讀」成員(即可以看到共享成員的計算機,但不共享她自己的計算機)。

查詢是爲給定用戶找到用戶可以看到的計算機。用戶可以看到她自己的所有電腦。她還可以看到其他用戶的任何計算機,這些計算機都是她所熟悉的並正在分享給該組的其他用戶。好吧,這沒有多大意義,所以這裏是在O目標(N^3)psudocode:

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的

感謝, 一切順利, 羅伯特

回答

1

我認爲這將做到沒有任何子查詢。免責聲明:這是我的頭頂,沒有經過測試。

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 or userId」應該讓你自己的電腦加上任何共享電腦。這可能不必要的巧妙:簡單的聯合可能更有效。

1

OK,我想你想爲上述規格表和查詢?

我從計算機是「分配給」一個給定的用戶,但可以共享的規格?

計算機(INT用戶id)

看一看這一點,讓我知道如果你想改變任何規格。

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

啊,謝謝,這看起來像我現在正在用ORM做...但是有兩個子類,這個查詢是否有效?是否值得將其視爲物化視圖? – 2009-09-30 10:14:36

+0

是的,每臺計算機只有一個用戶,但每個用戶可能有多臺計算機;謝謝! – 2009-09-30 10:17:49

+0

子查詢不是必需的,你可以修改它,但這是我輸入它的方式,因爲我閱讀你的問題X-)。 如果表上的索引是好的,我不認爲你會有太多的問題。另外,你可能想使用param使用查詢或表函數。另外,如果這些值不會定期更改,而且不會緩存這些值,那麼您甚至可以爲該選擇添加一個額外的字段,指示計算機是直接的,還是與其他人共享的。緩存這些值可能會使事情變得更快,但請記住在更新,刪除和插入時清除緩存 – 2009-09-30 10:45:27