0

ニハス

phpBBのようなすべての情報を含む古典的なフォーラムインデックスを生成するためのデータを受信するためのクエリに問題があります。

私のテーブルは次のようになります。

categories:
  gategory varchar(50)  -> primary key

forums:
  id int -> primary key
  name varchar(255)
  description text
  category varchar(50)  -> foreign key to category

topics:
  id int -> primary key
  forum_id int -> foreign key to forums
  subject varchar(255)

posts:
  id int -> primary key
  topic_id int -> foreign key to topics
  user_id int -> foreign key to users
  post text
  create_date datetime
  modify_date timestramp, on_update(current_time)

users:
  id int -> primary key
  username varchar(32)
  password varchar(32)

そして、それはとても簡単なことです。それから私はクエリを作成し始めました、そしてそれは(私の世界では)かなり速く非常に複雑になりました。取得したい:

catories:
  forums:
    name,
    description,
    count(topics)
    count(posts)
      last_post user_id
      last_post username
      last_post create_date

私は次のように動作するクエリになりました:

SELECT
  f.id              as fid,
  f.name            as name,
  f.description     as description,
  f.category        as category,
  ( SELECT COUNT(*)
    FROM forum_topics
    WHERE forum_id = f.id
  )                 as topics,
  ( SELECT COUNT(*)
    FROM forum_posts fp
    WHERE fp.topic_id IN (
      SELECT id
      FROM forum_topics
      WHERE forum_id = f.id
    )
  )                 as posts,
  lp.user_id        as lp_userid,
  u.username        as lp_username,
  lp.create_date    as lp_date
FROM forums f
LEFT OUTER JOIN (
  SELECT p.create_date, p.user_id, t.forum_id
  FROM forum_topics t
  INNER JOIN forum_posts p ON ( t.id = p.topic_id )
  ORDER BY p.create_date DESC
) lp ON (lp.forum_id = f.id)
LEFT OUTER JOIN users u ON ( u.id = lp.user_id )
GROUP BY category, f.order

大丈夫だよ; 動作しますが、パフォーマンスが非常に悪くなります。ですから、この場所にいる賢い人たちの中には、クエリを最適化する方法、いくつかのインデックスをいくつかのスマートな場所に配置する方法、またはよりスマートな方法でスキーマを再構築する方法についてアドバイスをくれる人がいるのではないかと思っていました。

// 事前にどうもありがとうございました

4

1 に答える 1

1

基本的なクエリは、すべてのテーブルをその性質の次元に沿って結合することです。これにより、最後の投稿を除くすべてが取得されます。

次のクエリは標準のSQLを使用しており、mysqlとSQL Serverの両方で機能するはずです(タイプミスを除く)。

SELECT
  f.category,
  f.id,
  f.name,
  f.description,
    count(distinct t.id) AS topics,
    count(distinct p.id) AS posts,
    min(lastuser.id),
    min(lastuser.username),
    min(p.create_date)
FROM posts p
JOIN users u ON p.user_id = u.id
JOIN topics t ON p.topic_id = t.id
JOIN forums f ON t.forum_id = f.id
JOIN (SELECT
        t.forum_id,
        u.id,
        u.username,
        p.create_date
        FROM posts p
        JOIN topics t ON p.topic_id = t.id
        JOIN users u ON p.user_id = u.id
        JOIN (SELECT
               t.forum_id, max(p.id) AS max_postid
              FROM posts p
              JOIN topics t ON p.topic_id = t.id
              GROUP BY t.forum_id
              ) lastpost ON p.id = lastpost.max_postid
             AND t.forum_id = lastpost.forum_id
       ) lastuser on lastuser.forum_id = f.id
GROUP BY f.category, f.id, f.name, f.description

別の複雑な結合セットによって最後のユーザーを取得します。クエリは、投稿が単調に割り当てられていることを前提としているため、最新の投稿の投稿IDが最も高くなります。

他のアプローチがあります。特に、SQL Serverはウィンドウ関数をサポートしているため、クエリが簡素化されます。

于 2012-05-11T00:39:39.413 に答える