2012-01-10 15 views
2

私はASP.NETメンバシップを使用していますが、その上にユーザーとの関係が1対多のテーブルをいくつか追加しました。カウントを使用して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分91人のユーザーのための11秒!

+0

はい、私はDBを吸うことを知っています。しかし、私は本当にそれらの番号を持っているが、私はそれらを得る方法の手掛かりを持っていない – BCartolo

+0

どのSQL Serverのバージョンを使用していますか? – Quassnoi

+0

Microsoft SQL Server 2008 R2標準 – BCartolo

答えて

2

速いヒットとして、最後にcross joinを取り出してください。あなたはそれを使用しておらず、あなたの結果を増やし、減速させるだけです。ユーザーはすべてのツールを持っていない可能性があればということ

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 

注:

また、あなただけそうのように、group byを保存し、RDBMSは、クエリを並列化することができます参加する前にカウントを行うことができますinnerの代わりにLEFTの結合を行い、次に*Count列のすべてをcoalesce(Count, 0)でラップします。

+0

私は今それを試みている。ありがとう! – BCartolo

+0

@BCartolo - ちょっと早くこのクエリを編集しました。あなたが見つけたものを教えてください:) – Eric

+0

@BCartolo、あなたはcount(1)に関連するテーブルのLEFT JOINsに変更する必要があります。あなたがペン内で使用されていないが、ノートブックやルーラーなどでは使用されていない所有者は、それは除外されます。 「カウント」にLEFT JOINを実行することで、エイリアスは、カウントがそのようなサブカテゴリカウントの1つにしか含まれていなくても、すべてのメンバーがそれぞれのカウントに含まれることを保証します。 – DRapp

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

+0

このオプションは、他のものと同じ速さで動作します。しかし、もう1つが最初に投稿されました。とにかく、ありがとう! – BCartolo