サンプルテーブル(log_xs)
| フィールド | 型 | Null | 主キー | デフォルト | コメント |
|---|---|---|---|---|---|
| id | int(11) | NO | PRI | ID | |
| user_id | int(11) | NO | ユーザーID | ||
| event_no | int(11) | NO | イベント番号 | ||
| event_cnt | int(11) | NO | イベント実行回数 | ||
| created_ip_addr | varchar(40) | YES | 生成IPアドレス | ||
| modfied_ip_addr | varchar(40) | NO | 更新IPアドレス | ||
| created | datetime | NO | 生成日時 | ||
| modified | timestamp | YES | CURRENT_TIMESTAMP | 更新日時 |
データを倍にするSQL
INSERT INTO log_xs( user_id ,event_no ,event_cnt ,created_ip_addr ,modfied_ip_addr ,created) ( SELECT user_id ,event_no ,event_cnt ,created_ip_addr ,modfied_ip_addr ,created FROM log_xs );1件レコードから上記のSQLを28回実行すると1億件レコードができあがる。(134217728件)
The total number of locks exceeds the lock table size
innodb_buffer_pool_size = 16M↓16Mから256Mに書き換え
innodb_buffer_pool_size = 256MXAMPP Control PanelでMySQLを再起動する。
利点
探索SQLの実行速度が速くなる。無駄な処理を省いたり、キャッシュの有効活用により速くなるらしい。欠点
分割する列を主キーにする必要がある。#1503 - A PRIMARY KEY must include all columns in the table's partitioning function参考
データ分割方法
パーティションのデータ分割方法には、「RANGE、LIST、HASH、KEY」がある。サンプルテーブル log_ys
| フィールド | 型 | 主キー | コメント |
|---|---|---|---|
| id | int(11) | PRI | ID(自動採番:auto increment) |
| user_id | int(11) | ユーザーID | |
| event_no | int(11) | イベント番号 | |
| created←分割基準 | datetime | PRI←分割基準にするため主キーとする | 生成日時 |
log_ysのサンプルデータ
| id | user_id | event_no | created |
|---|---|---|---|
| 2204636 | 2 | 7 | 2015/9/2 00:00:00 |
| 2204637 | 2 | 9 | 2015/10/2 00:00:00 |
| 2204638 | 2 | 10 | 2015/8/2 00:00:00 |
| 2204639 | 2 | 11 | 2015/7/2 00:00:00 |
| 2204643 | 2 | 12 | 2015/6/2 00:00:00 |
| 2204644 | 2 | 13 | 2015/5/2 00:00:00 |
| 2204645 | 2 | 14 | 2015/4/2 00:00:00 |
| 2204646 | 2 | 15 | 2015/3/2 00:00:00 |
| 2204647 | 2 | 16 | 2015/2/2 00:00:00 |
| 2204648 | 2 | 17 | 2015/1/2 00:00:00 |
| 2204649 | 2 | 18 | 2014/12/2 00:00:00 |
| 2204650 | 2 | 19 | 2013/12/2 00:00:00 |
| 2204651 | 8 | 8 | 0000-00-00 00:00:00 |
| 2204634 | 2 | 6 | 2015/11/2 00:00:00 |
| 1 | 2 | 3 | 2015/12/2 00:00:00 |
| 2204632 | 2 | 4 | 2015/12/3 00:00:00 |
| 2204633 | 2 | 5 | 2015/12/31 00:00:00 |
| 2204652 | 7 | 7 | 2015/12/31 00:00:00 |
パーティション分割をするSQL
ALTER TABLE log_ys
PARTITION BY RANGE COLUMNS(created)
(
PARTITION p20150901 VALUES LESS THAN ('2015-09-01') ENGINE = InnoDB,
PARTITION p20151001 VALUES LESS THAN ('2015-10-01') ENGINE = InnoDB,
PARTITION p20151101 VALUES LESS THAN ('2015-11-01') ENGINE = InnoDB,
PARTITION p20151201 VALUES LESS THAN ('2015-12-01') ENGINE = InnoDB,
PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE=InnoDB
);
※日付は昇順にすること。
パーティションを確認するSQL
SELECT TABLE_SCHEMA,TABLE_NAME,PARTITION_NAME,PARTITION_ORDINAL_POSITION,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='log_ys';出力
| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | TABLE_ROWS |
|---|---|---|---|---|
| cake_demo | log_ys | p20150901 | 1 | 11 |
| cake_demo | log_ys | p20151001 | 2 | 0 |
| cake_demo | log_ys | p20151101 | 3 | 0 |
| cake_demo | log_ys | p20151201 | 4 | 0 |
| cake_demo | log_ys | pmax | 5 | 3 |
パーティションを解除するSQL
ALTER TABLE log_ys REMOVE PARTITIONING;
パーティションを削除
※データごと削除ALTER TABLE log_ys DROP PARTITION p20151101;
パーティションを挿入
ALTER TABLE log_ys REORGANIZE PARTITION pmax INTO (
PARTITION p20160101 VALUES LESS THAN ('2016-01-01'),
PARTITION pmax VALUES LESS THAN MAXVALUE);
パーティション挿入でエラーになる例
最後のパーティションが「2016-01-01」であるなら、この日付以降の日付で分割しなければならない。
ALTER TABLE log_ys REORGANIZE PARTITION pmax INTO (
PARTITION p20140101 VALUES LESS THAN ('2014-02-01'),
PARTITION pmax VALUES LESS THAN MAXVALUE);
エラー
#1493 - VALUES LESS THAN value must be strictly increasing for each partition
IGNORE指定の例
INSERT IGNORE INTO nekos (id,text1) VALUES(2,'kani');
nekosテーブル idはPRIMARY
| id | val1 | text1 | test_date | test_dt |
|---|---|---|---|---|
| 1 | 1 | neko | 2014/4/1 | 2014/12/12 0:00 |
| 2 | 2 | kani | 2014/4/2 | 2014/12/12 0:00 |
| 4 | 4 | buta | 2014/4/4 | 2014/12/12 0:00 |
| 5 | 3 | yagi | 2014/4/3 | 2014/12/12 0:00 |
INSERT IGNORE INTO nekos (id,text1) VALUES(2,'kani');idがユニーク(PRIMARY)であり、id=2はテーブル上に存在するため、新規レコードは追加されない。なおエラーにはならない。
INSERT IGNORE INTO nekos (id,text1) VALUES(12,'kani');idがユニークであり、id=12はテーブル上に存在しないので、新規レコードは追加される。
INSERT IGNORE INTO nekos (val1,text1) VALUES(2,'kani');val1,text1は重複値であるが、どちらもユニークでないため、新規レコードは追加される。
テーブルデータ量を取得するSQL
SELECT table_name, engine, table_rows, # テーブルの行数 avg_row_length, # 平均行容量(1レコードあたりの平均容量) (data_length + index_length) AS all_length, # テーブルの容量サイズ(byte) data_length, index_length FROM information_schema.tables WHERE table_schema = 'animal_park' # DB名
テーブルデータ量の例
| engine | table_name | table_rows | avg_row_length | all_length | data_length | index_length |
|---|---|---|---|---|---|---|
| InnoDB | kanis | 10 | 1638 | 16384 | 16384 | 0 |
| InnoDB | log_xs | 120997206 | 82 | 10022289408 | 10022289408 | 0 |
| InnoDB | log_ys | 20 | 5734 | 229376 | 114688 | 114688 |
| InnoDB | nekos | 9 | 1820 | 16384 | 16384 | 0 |
説明表
| フィールド | 説明 |
|---|---|
| table_name | テーブル名 |
| engine | innoDB,MyISAMなど |
| table_rows | レコード件数であるが、innoDBである場合、正確値でなく見積もり値となる。 |
| avg_row_length | 平均レコードサイズ(byte) |
| all_length | 合計データ量(データ量+インデックスサイズ) |
| data_length | データ量(byte) |
| index_length | インデックスサイズ(byte)。テーブル内のインデックスが占めるサイズ。 |
SELECT table_schema, sum(data_length) AS db_length # DB容量 FROM information_schema.tables WHERE table_schema = 'animal_park' # DB名
| table_schema | db_length |
|---|---|
| animal_park | 65536 |
INSERT INTO nekos (val1,text1,test_date,test_dt) (select val1,text1,test_date,test_dt FROM nekos WHERE id = 5);
SQL実行前のnekosテーブル
| id | val1 | text1 | test_date | test_dt |
|---|---|---|---|---|
| 4 | 4 | buta | 2014/4/4 | 2014/12/12 0:00 |
| 5 | 3 | yagi | 2014/4/3 | 2014/12/12 0:00 |
| 6 | 3 | ari | 2014/4/3 | 2014/12/12 0:00 |
SQLを実行する
INSERT INTO nekos (val1,text1,test_date,test_dt) (select val1,text1,test_date,test_dt FROM nekos WHERE id = 5);
SQL実行後のnekosテーブル
| id | val1 | text1 | test_date | test_dt |
|---|---|---|---|---|
| 4 | 4 | buta | 2014/4/4 | 2014/12/12 0:00 |
| 5 | 3 | yagi | 2014/4/3 | 2014/12/12 0:00 |
| 6 | 3 | ari | 2014/4/3 | 2014/12/12 0:00 |
| 15 | 3 | yagi | 2014/4/3 | 2014/12/12 0:00 |
誤
以下のSQLでは主キーのエラーが起こるINSERT INTO nekos (select * FROM nekos WHERE id = 5);
CREATE TEMPORARY TABLE tmp SELECT * from animals where id=1234; ALTER TABLE tmp drop id; INSERT INTO animals SELECT 0,tmp.* FROM tmp; DROP TABLE tmp;プログラムに埋め込んでの使用はふさわしくない。
SET @a1='neko'; SELECT * FROM nekos WHERE text1 = @a1;このSQLの用い方は、動的SQL、ダイナミックSQL、ストアドプロシージャとも呼ばれる。

SELECT * FROM nekos ORDER BY neko_date DESC LIMIT 1
旧式
nekosテーブル| id | neko_val | neko_name | neko_date | neko_group | neko_dt | note |
|---|---|---|---|---|---|---|
| 1 | 1 | ルドルフ | 2014/4/1 | 2 | 2014/12/12 0:00 | 字を学ぶ |
| 2 | 25 | 吾輩は猫 | 2016/6/24 | 1 | 2014/12/12 0:00 | 名前はまだない |
| 4 | 4 | 100万回生きた猫 | 2014/4/4 | 4 | 2014/12/12 0:00 | 100万回死んだ。 |
| 9 | 111 | イッパイアッテナ | 2014/4/1 | 3 | 2014/4/28 10:04 | 識字者 |
| 13 | 99 | ピーター | 2016/6/25 | 6 | 2016/1/25 12:12 | 畑を荒らすウサギ |
| 14 | 200 | ロイヤルアナロスタン | 2016/2/8 | 5 | NULL | 荒野を生き抜いた。 |
最大値のレコードを取得するSQL
最大日付のレコードを、すべてのフィールドと共に取得する。
SELECT *
FROM nekos
WHERE (neko_date) IN
(SELECT MAX(neko_date) FROM nekos );
| id | neko_val | neko_name | neko_date | neko_group | neko_dt | note |
|---|---|---|---|---|---|---|
| 13 | 99 | ピーター | 2016/6/25 | 6 | 2016/1/25 12:12 | 畑を荒らすウサギ |
注意:最大値や最小値が複数存在する場合
最小日付のレコードが2つあれば、取得されるレコードも2つである。SELECT * FROM nekos WHERE (neko_date) IN (SELECT MIN(neko_date) FROM nekos );
| id | neko_val | neko_name | neko_date | neko_group | neko_dt | note |
|---|---|---|---|---|---|---|
| 1 | 1 | ルドルフ | 2014/4/1 | 2 | 2014/12/12 0:00 | 字を学ぶ |
| 9 | 111 | イッパイアッテナ | 2014/4/1 | 3 | 2014/4/28 10:04 | 識字者 |
ALTER TABLE many_todos ADD id int not null primary key auto_increment; ALTER TABLE many_todos MODIFY id int FIRST;