web-dev-qa-db-ja.com

日時列でテーブルを分割する方法

Mysqlテーブルをdatetimeカラムでパーティション化したい。ある日、パーティションです。テーブル作成スクリプトは次のようになります。

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (day(ftime)) partitions 31;

しかし、ある日のデータを選択すると、パーティションが見つかりませんでした.selectステートメントは次のようになります:

explain partitions select * from raw_log_2011_4 where day(ftime) = 30;

別のステートメントを使用すると、パーティションを見つけることができましたが、ある日のデータを選択できませんでした。

explain partitions select * from raw_log_2011_4 where ftime = '2011-03-30';

ある日のデータを選択してパーティションを利用する方法を教えてくれる人はいますか?

15
tinychen

パーティション・プルーニング を使用できないため、HASHによるパーティションは日時列では非常に悪い考えです。 MySQLのドキュメントから:

プルーニングは、HASHまたはKEYによってパーティション化されたテーブルの整数列でのみ使用できます。たとえば、テーブルt4に対する次のクエリでは、dobがDATE列であるため、プルーニングを使用できません。

SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';

ただし、テーブルがINT列に年の値を格納している場合は、WHERE year_col> = 2001 AND year_col <= 2005のクエリをプルーニングできます。

したがって、TO_DAYS(DATE())の値を追加のINTEGER列に格納して、プルーニングを使用できます。

別のオプションは、RANGEパーティショニングを使用することです。

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
  PARTITION BY RANGE( TO_DAYS(ftime) ) (
    PARTITION p20110401 VALUES LESS THAN (TO_DAYS('2011-04-02')),
    PARTITION p20110402 VALUES LESS THAN (TO_DAYS('2011-04-03')),
    PARTITION p20110403 VALUES LESS THAN (TO_DAYS('2011-04-04')),
    PARTITION p20110404 VALUES LESS THAN (TO_DAYS('2011-04-05')),
    ...
    PARTITION p20110426 VALUES LESS THAN (TO_DAYS('2011-04-27')),
    PARTITION p20110427 VALUES LESS THAN (TO_DAYS('2011-04-28')),
    PARTITION p20110428 VALUES LESS THAN (TO_DAYS('2011-04-29')),
    PARTITION p20110429 VALUES LESS THAN (TO_DAYS('2011-04-30')),
    PARTITION future VALUES LESS THAN MAXVALUE
  );

次のクエリは、パーティションp20110403のみを使用します。

SELECT * FROM raw_log_2011_4 WHERE ftime = '2011-04-03';
20
Steyx

こんにちはあなたはテーブル定義が間違っているテーブルの定義で間違ったパーティションをやっています:

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (TO_DAYS(ftime)) partitions 31;

そしてあなたの選択コマンドは次のようになります:

explain partitions 
    select * from raw_log_2011_4 where TO_DAYS(ftime) = '2011-03-30';

上記のコマンドは、TO_DAYSコマンドを次のように使用する場合と同様に、必要なすべての日付を選択します

mysql> SELECT TO_DAYS(950501);
        -> 728779
mysql> SELECT TO_DAYS('2007-10-07');
        -> 733321

TO_DAYS ASを使用する理由MySQLオプティマイザは、パーティションプルーニングの目的で2つの日付ベースの関数を認識します。1.TO_DAYS()2.YEAR()

これで問題が解決します。

9
Vineet1982

最近、これに関連するMySQLブログの投稿を http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html で読みました。

5.1より前のバージョンでは、日付に基づいてパーティショニングを行うために特別な体操が必要でした。上記のリンクはそれについて議論し、例を示しています。

バージョン5.5以降では、日付や文字列などの非数値を使用して直接パーティション化を行うことができました。

1
John Rocha

CHARは使用せず、VARCHARを使用してください。これは多くのスペースを節約し、I/Oを減らし、クエリを高速化します。

reporterip:(46)は、IPv6であっても、IPアドレスに対して不必要に大きくなります。それを16バイトに縮小する方法を含む詳細な議論については 私のブログ を参照してください。

PARTITION BY RANGE(TO_DAYS(...)) @Steyxが提案したとおりですが、50を超えるパーティションはありません。パーティションが多いほど、「プルーニング」にもかかわらず、クエリが遅くなります。 HASHパーティショニングは基本的に役に立ちません。

パーティション分割の詳細、特に見ているタイプ 。これには、時間の経過とともにスライドする一連のパーティションのコードが含まれます。

0
Rick James