Оптимизировать SQL-запрос, используя количество - PullRequest
2 голосов
/ 10 января 2012

Я использую членство в ASP.NET, и, кроме того, я добавил несколько таблиц с отношениями один-ко-многим с пользователями.

У одного пользователя много ручек, ноутбуков и т. Д.

Я кодирую собственного провайдера членства и изменил запрос на выборку, чтобы получить всю информацию о пользователе, а также количество перьев, которые есть у пользователя, и общее количество «инструментов», но запрос, очевидно, выполняется катастрофически. Есть ли способ получить эту информацию? Вот что я пробовал:

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 пользователя!

Ответы [ 2 ]

3 голосов
/ 10 января 2012
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)
2 голосов
/ 10 января 2012

В качестве быстрого удара, уберите cross join в самом конце - вы его не используете, а просто умножаете свои результаты и замедляете процесс.

Кроме того, вы можете просто сделатьсчитает до присоединения, что сохранит group by и позволит СУБД распараллелить запрос, например так:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...