2012-01-10 56 views
2

我使用ASP.NET成員資格,最重要的是我添加了一些與用戶有一對多關係的表。使用計數優化SQL查詢

一個用戶有很多筆,筆記本等

我編碼一個自定義的成員提供和已經修改了選擇查詢檢索所有關於用戶以及用戶具有筆的數量和信息「工具」的總數,但查詢顯然是災難性的。 無論如何得到這些信息? 這是我曾嘗試:

SET STATISTICS TIME ON 
SELECT m.Email, m.PasswordQuestion, m.IsApproved, m.CreateDate, m.LastLoginDate, 
     u.LastActivityDate, m.LastPasswordChangedDate, u.UserId, m.IsLockedOut, 
     m.LastLockoutDate, CAST(m.Comment as nvarchar(max)) as Comment, 
     COUNT(DISTINCT cl.Id) AS NumberOfPens, 
     COUNT(DISTINCT cf.Id)+ 
      COUNT(DISTINCT cm.Id) + 
      COUNT(DISTINCT ce.Id) + 
      COUNT(DISTINCT cl.Id) + 
      COUNT(DISTINCT cp.Id) + 
      COUNT(DISTINCT csl.Id)+ 
      COUNT(DISTINCT cs.Id) + 
      COUNT(DISTINCT cshl.Id) AS NumberOfTools 
FROM aspnet_Membership AS m 
     INNER JOIN aspnet_Users AS u ON m.UserId = u.UserId 
     INNER JOIN Pens AS cf ON u.UserId = cf.Owner 
     INNER JOIN Notebooks AS cm ON u.UserId = cm.Owner 
     INNER JOIN Rulers AS ce ON u.UserId = ce.Owner 
     INNER JOIN Calculators AS cl ON u.UserId = cl.Owner 
     CROSS JOIN aspnet_Applications AS a 
GROUP BY u.UserId, m.Email, m.PasswordQuestion, m.IsApproved, 
     m.CreateDate, m.LastLoginDate, u.LastActivityDate, 
     m.LastPasswordChangedDate, m.IsLockedOut, m.LastLockoutDate, 
     CAST(m.Comment as nvarchar(max)) 

SET STATISTICS TIME OFF 

9分鐘11秒91級的用戶!

+0

是的,我知道我吮吸DB。但我真的很想擁有這些數字,但我不知道如何獲取這些數字 – BCartolo 2012-01-10 16:46:57

+0

您正在使用哪種SQL Server版本? – Quassnoi 2012-01-10 16:49:40

+0

Microsoft SQL Server 2008 R2標準 – BCartolo 2012-01-10 18:29:33

回答

2

作爲一個快速打擊,最終拿出cross join - 你沒有使用它,它只是增加你的結果並放慢速度。

此外,你可以做接合前的計數,這將節省group by並允許RDBMS並行查詢,像這樣:

SELECT  
    m.Email, 
    m.PasswordQuestion, 
    m.IsApproved, 
    m.CreateDate, 
    m.LastLoginDate, 
    u.LastActivityDate, 
    m.LastPasswordChangedDate, 
    u.UserId, 
    m.IsLockedOut, 
    m.LastLockoutDate, 
    CAST(m.Comment as nvarchar(max)) as Comment, 
    PenCount AS NumberOfPens, 
    PenCount + NotebookCount + RulerCount + CalculatorCount AS NumberOfTools 
FROM 
    aspnet_Membership AS m 
    INNER JOIN aspnet_Users AS u ON 
     m.UserId = u.UserId 
    INNER JOIN (select owner, count(1) as PenCount from Pens group by owner) AS cf ON 
     u.UserId = cf.Owner 
    INNER JOIN (select owner, count(1) as NotebookCount from Notebooks group by owner) AS cm ON 
     u.UserId = cm.Owner 
    INNER JOIN (select owner, count(1) as RulerCount from Rulers group by owner) AS ce ON 
     u.UserId = ce.Owner 
    INNER JOIN (select owner, count(1) as CalculatorCount from Calculators group by owner) AS cl ON 
     u.UserId = cl.Owner 

需要注意的是,如果一個用戶可能沒有所有工具,你會想要做LEFT連接代替inner連接,然後將所有*Count列與coalesce(Count, 0)包裝在一起。

+0

好的。我現在正在嘗試。謝謝! – BCartolo 2012-01-10 16:42:50

+0

@BCartolo - 我剛剛編輯此查詢的速度也更快一些。讓我知道你在找什麼:) – Eric 2012-01-10 16:46:50

+0

@BCartolo,你可能需要改變與count(1)相關聯的表上的LEFT JOIN。如果您的筆擁有者不在筆內使用,但在筆記本,統治者等中使用,則會被忽略。通過對「count」別名執行LEFT JOIN,將確保所有成員都將包含在其各自的計數中,即使計數僅在一個此類子類別計數中。 – DRapp 2012-01-10 16:47:43

3
SELECT m.Email, m.PasswordQuestion, m.IsApproved, m.CreateDate, m.LastLoginDate, 
     u.LastActivityDate, m.LastPasswordChangedDate, u.UserId, m.IsLockedOut, 
     m.LastLockoutDate, CAST(m.Comment as nvarchar(max)) as Comment, 
     penCount, 
     notebookCount + rulerCount + calculatorCount AS toolCount 
FROM aspnet_Membership m 
JOIN aspnet_Users u 
ON  u.userId = m.userId 
CROSS APPLY 
     (
     SELECT COUNT(*) 
     FROM pens 
     WHERE owner = u.UserId 
     ) p (penCount) 
CROSS APPLY 
     (
     SELECT COUNT(*) 
     FROM notebooks 
     WHERE owner = u.UserId 
     ) n (notebookCount) 
CROSS APPLY 
     (
     SELECT COUNT(*) 
     FROM rulers 
     WHERE owner = u.UserId 
     ) r (rulerCount) 
CROSS APPLY 
     (
     SELECT COUNT(*) 
     FROM calculators 
     WHERE owner = u.UserId 
     ) c (calculatorCount) 
+0

謝謝我也會嘗試這個選項 – BCartolo 2012-01-10 18:30:51

+0

這個選項的工作速度與其他選項一樣快。但另一個被首先發布。不管怎麼說,多謝拉! – BCartolo 2012-01-10 18:57:36