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';
ある日のデータを選択してパーティションを利用する方法を教えてくれる人はいますか?
パーティション・プルーニング を使用できないため、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';
こんにちはあなたはテーブル定義が間違っているテーブルの定義で間違ったパーティションをやっています:
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()
これで問題が解決します。
最近、これに関連するMySQLブログの投稿を http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html で読みました。
5.1より前のバージョンでは、日付に基づいてパーティショニングを行うために特別な体操が必要でした。上記のリンクはそれについて議論し、例を示しています。
バージョン5.5以降では、日付や文字列などの非数値を使用して直接パーティション化を行うことができました。
CHAR
は使用せず、VARCHAR
を使用してください。これは多くのスペースを節約し、I/Oを減らし、クエリを高速化します。
reporterip
:(46)は、IPv6であっても、IPアドレスに対して不必要に大きくなります。それを16バイトに縮小する方法を含む詳細な議論については 私のブログ を参照してください。
PARTITION BY RANGE(TO_DAYS(...))
@Steyxが提案したとおりですが、50を超えるパーティションはありません。パーティションが多いほど、「プルーニング」にもかかわらず、クエリが遅くなります。 HASH
パーティショニングは基本的に役に立ちません。
パーティション分割の詳細、特に見ているタイプ 。これには、時間の経過とともにスライドする一連のパーティションのコードが含まれます。