1

1 つの InnoDB MySQL テーブルを使用して、PHP サイトの「アクティビティ ログ」を作成したいと考えています。ウェブサイトにアクセスした人は誰でもテーブルに新しいレコードを挿入し、それが記録されます...

  • 彼らのIPアドレス
  • サインインしているアカウントの ID (サインインしていない場合は null)
  • 彼らがサーバーに行ったリクエスト
  • リクエストを受信した日時
  • ユーザーエージェントが送信されましたが、PHP スクリプトがボットであると判断した場合のみ(それ以外の場合は null)

同時に、テーブルを使用して...

  • 各ページが年/月/日/などに受け取るヒット数を決定する
  • 年/月/日/などのユニークビジター数を決定する
  • 実用的であれば、PHP スクリプトを使用してオンザフライで以前の情報を取得し、必要に応じてボット リクエストを除外します。

私が念頭に置いている次の表について、いくつかの質問 (およびいくつかの推論) があります。

CREATE TABLE `activity` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `ip` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `account` int(11) unsigned DEFAULT NULL,
  `request` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `time` time NOT NULL,
  `year` year(4) NOT NULL,
  `month` tinyint(2) unsigned NOT NULL,
  `day` tinyint(2) unsigned NOT NULL,
  `bot` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
)
  1. このスタイルのロギングは実用的ですか? 実用的な意味の挿入と選択はミリ秒単位で実行できます。この方法で多くのレコードを生成できることはわかっていますが、やりたいことすべてを達成するためのより良い方法があるかどうかは完全にはわかりません.

  2. さらに、「今日」のヒット数を選択して、提供される各ページの下部に配置することは実用的でしょうか? 私は比較的大規模なデータベースでの作業に慣れていませんが、どのクエリが高速で、どのクエリが苦痛になるかをまだ学んでいます。

  3. 主キーを保持する必要がありますか? 気まぐれに戻って必要な行を編集するためにそれを使用できますが (重要な理由で自分が実際にそうしているとは思えません)、INSERT が大幅に遅くなりますか? 何か利点はありますか?同じ理由で、これ以上インデックスを追加するべきではありません。外部キー (アカウント列用) を含めますか?

  4. 現在の日付と時刻を取得する代替手段は実用的ですか? 私は最初、このテーブルを 1 つの DATETIME 列で開始しましたが、このようなテーブルでは日付情報を分割する列が役立つ可能性があることをどこかで読みました。たとえば、「今日」のヒット数を数えたい場合、結果を次のように制限できます...

    WHERE year="2012" AND month="02" AND day="16"
    

    ...とは対照的に...

    WHERE date > "2012-02-15 23:59:59"
    

前もって感謝します!

4

2 に答える 2

2

これまでのところ、ログ テーブルは妥当なようです。timeしかし、列, year,の代わりにmonthday私はTIMESTAMP4 バイトだけを使用します。次に、この列のインデックスを追加します。

範囲検索を使用したクエリがある場合は、良好な応答時間が得られるはずです。

WHERE created >= "2011-01-01 00:00:00"
    AND created < "2012-01-01 00:00:00"
于 2012-06-01T01:42:05.680 に答える
1

この形式のロギングは実用的ですが、パーティショニング (およびサブパーティショニング) を使用するとメリットがあります: http://dev.mysql.com/doc/refman/5.1/en/partitioning.html

アクティビティ ログを保存しているため、時間の経過とともに非常に大きなデータ セットが存在する可能性があります。特定の月と年を調べたいので、パーティショニングは特に便利です。

たとえば、日付列のデータ型が DATE または DATETIME の場合、次のようにすることができます。

PARTITION BY RANGE (MONTH(the_date))
(PARTITION p0 VALUES LESS THAN (0),
 PARTITION p1 VALUES LESS THAN (1),
 PARTITION p2 VALUES LESS THAN (2),
...[and so on up to 12]);

これにより、月ごとのデータのパーティションが得られます。異なるパーティションでテストしたら、"explain partitions select * from..." を使用してクエリを実行してみてください。クエリがどのように実行され、どのパーティションがスキャンされるかを確認できます。パーティショニングへの最善のアプローチは、最も一般的なクエリに合わせて調整する必要がある可能性があります。たとえば、主に過去 30 日間のデータを見ていますか? 毎月のスナップショット? カスタムの日付範囲? これらはすべて、パーティションの構造に影響を与える可能性があります。

さらに一歩進んで、各パーティションにサブパーティションを含めることができます。このために、ハッシュ パーティションを使用できます: http://dev.mysql.com/doc/refman/5.1/en/partitioning-hash.html

主キーの質問は、パーティショニングの影響も受けます。テーブルの主キー (および一意のキー) は、パーティション分割で使用されるすべての列を使用する必要があります。

于 2012-06-01T04:05:45.763 に答える