0

過去2日間、運転に問題があります。私は基本的に次の順序で継承を持つ4つのテーブルを持っています:

             users
               |
categories   blogs
     |      |     |
     ---- pages visits

したがって、ユーザーは多くのページと訪問を持つ多くのブログを持っています。各ページもカテゴリに属しています。

私が欲しいのは、次のカウントが関連付けられているすべてのユーザーを抽出することです。

  1. 各ユーザーが持っているブログの総数
  2. 各ユーザーの総ページ数
  3. 各ユーザーがブログを持っているカテゴリの総数
  4. 各ユーザーの合計訪問数
  5. 各ユーザーの合計訪問者数(訪問数ですが、個別のip_addressでカウントされます)

私の質問は次のとおりです。

SELECT
    u.id
    u.username,
    COUNT(b.id) as blogs_count,
    COUNT(p.id) as pages_count,
    COUNT(v.id) as visits_count,
    COUNT(distinct ip_address) as visitors_count
    COUNT(c.id) as categories_count
FROM
    users u
LEFT JOIN
    blogs b ON(b.user_id=u.id)
LEFT JOIN
    pages p ON(p.blog_id=b.id)
LEFT JOIN
    visits v ON(v.blog_id=b.id)
LEFT JOIN
    categories c ON(v.category_id=c.id)
GROUP BY u.id, blogs_count, pages_count, visits_count, 
         visitors_count, categories_count

24人のユーザーをカウントする必要がありますが、30万回近くアクセスしているという事実を考えると、SQLデータベースが永遠にハングアップし、おそらく数百万行をプルしようとしています。私はdbの第一人者ではなく、それは明らかです。誰かが私を正しい方向に向けることができますか?そうすれば、何百万ものレコードでも(もちろん適切なハードウェアを使用して)うまく実行できる優れたクエリを作成できますか?

4

2 に答える 2

0
SELECT
    u.id
    u.username,
    COUNT(b.id) as blogs_count,
    COUNT(p.id) as pages_count,
    COUNT(v.id) as visits_count,
    COUNT(distinct ip_address) as visitors_count
    COUNT(c.id) as categories_count
FROM
    users u
LEFT JOIN
    blogs b ON(b.user_id=u.id)
LEFT JOIN
    pages p ON(p.blog_id=b.id)
LEFT JOIN
    visits v ON(v.blog_id=b.id)
LEFT JOIN
    categories c ON(v.category_id=c.id)
GROUP BY u.id

blogs_count、pages_count、visits_count、visitors_count、categories_countをグループからステートメントで削除してみてください。

于 2012-07-31T16:05:19.620 に答える
0

これを試して:

SELECT    u.id,
          u.username,
          COUNT(b.id)                     AS blogs_count,
          COALESCE(MAX(p.pagecnt), 0)     AS pages_count,
          COALESCE(MAX(v.visitscnt), 0)   AS visits_count,
          COALESCE(MAX(v.visitorscnt), 0) AS visitors_count,
          COALESCE(MAX(c.catcnt), 0)      AS categories_count
FROM      users u
LEFT JOIN blogs b ON u.id = b.user_id
LEFT JOIN (
          SELECT   blog_id, 
                   COUNT(*) AS pagecnt
          FROM     pages
          GROUP BY blog_id
          ) p ON b.id = p.blog_id
LEFT JOIN (
          SELECT   blog_id, 
                   COUNT(*) AS visitscnt, 
                   COUNT(DISTINCT ip_address) AS visitorscnt
          FROM     visits
          GROUP BY blog_id
          ) v ON b.id = v.blog_id
LEFT JOIN (
          SELECT   aa.id,
                   COUNT(DISTINCT dd.id) AS catcnt
          FROM     users aa
          JOIN     blogs bb ON aa.id = bb.user_id
          JOIN     pages cc ON bb.id = cc.blog_id
          JOIN     categories dd ON cc.category_id = dd.id
          GROUP BY aa.id
          ) c ON u.id = c.id
GROUP BY  u.id, 
          u.username

壊す

これは、PGSQL、SQL-ServerなどのさまざまなDBMSでも機能するはずです。

課題は、このような1:M関係の階層があり、それらをすべて結合すると、さまざまなタイプのカウントを簡単に破棄できることです(場所によっては個別のカウントが必要ですが、他の場所では合計カウントが必要なため)。

私がやることに決めたのは、最初に各ページの数をサブ選択し、訪問者/個別の訪問者をでグループ化することblog_idです。これによりblog_id、ブログテーブルの副選択を結合した後でも、ごとに1つの行のみを取得できます。

カテゴリ数については、ユーザーごとに個別のカテゴリを数える必要がありますが、課題は、カテゴリが関係階層内で(ページテーブルに)深くリンクされているため、代わりにuser_idで結合する別の副選択を作成する必要があります。 blog_id。

このクエリに含まれる副選択の数が多い場合でも、2つの副選択が相互に結合していないため、非常に高速である必要があります。結合の両側にインデックス付きテーブル(サブセレクトは実際にはインデックスなしの一時テーブル)がある限り、問題はありません。

于 2012-07-31T16:27:58.547 に答える