# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(2, 'test_user');
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:エラー
ERROR 1062 (23000): Duplicate entry 'test_user' for key 'user.name'
# テーブル削除
drop table user;
複数レコードにNULLがあるカラム場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, null),(2, null);
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:成功
Query OK, 0 rows affected (0.02 sec)
# テーブル削除
drop table user;
末尾にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(2, 'test_user ');
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:成功
Query OK, 0 rows affected (0.02 sec)
# テーブル削除
drop table user;
途中にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'testuser'),(1, 'test user');
# ユニークインデックスを貼る
alter table user add unique(id,name);
# 結果:成功
Query OK, 0 rows affected (0.02 sec)
# テーブル削除
drop table user;
先頭にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(1, ' test_user');
# ユニークインデックスを貼る
alter table user add unique(id,name);
# 結果:成功
Query OK, 0 rows affected (0.01 sec)
# テーブル削除
drop table user;
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(2, 'test_user');
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:エラー
ERROR 1062 (23000): Duplicate entry 'test_user' for key 'name'
# テーブル削除
drop table user;
複数レコードにNULLがあるカラム場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, null),(2, null);
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:成功
Query OK, 0 rows affected (0.02 sec)
# テーブル削除
drop table user;
末尾にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(2, 'test_user ');
# ユニークインデックスを貼る
alter table user add unique(name);
# 結果:エラー
ERROR 1062 (23000): Duplicate entry 'test_user' for key 'name'
# テーブル削除
drop table user;
途中にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'testuser'),(1, 'test user');
# ユニークインデックスを貼る
alter table user add unique(id,name);
# 結果:成功
Query OK, 0 rows affected (0.02 sec)
# テーブル削除
drop table user;
先頭にスペースがある場合
# テーブル作成
create table user (id int, name varchar(10));
# データ登録
insert into user values (1, 'test_user'),(1, ' test_user');
# ユニークインデックスを貼る
alter table user add unique(id,name);
# 結果:成功
Query OK, 0 rows affected (0.01 sec)
# テーブル削除
drop table user;
-- 区切り文字を「//」に変更する
DELIMITER //
-- make_sample_dataというテストデータ作成用プロシージャーを作成する
create procedure make_sample_data(in i int)
begin
declare count int default 0;
-- 繰り返し
while count < i do
set count = count + 1;
INSERT INTO user VALUES(count, MOD(count,2),CONCAT('usr_name_',count));
end while;
end
//
-- 区切り文字を「;」に戻す
DELIMITER ;
MySQL5.7 MyISAM
create table user(
id INT,
type INT,
name VARCHAR(255)
) engine MyISAM;
mysql> select version();
+------------+
| version() |
+------------+
| 5.7.41-log |
+------------+
1 row in set (0.00 sec)
select * from user where id = 5000;
+------+------+---------------+
| id | type | name |
+------+------+---------------+
| 5000 | 0 | usr_name_5000 |
+------+------+---------------+
0.00127125
◾️1件UPDATE
update user set name = 'name_5001' where id = 5001;
0.06670350
◾️1件DELETE
delete from user where id = 5002;
0.00380375
MySQL5.7 InnoDB
create table user(
id INT,
type INT,
name VARCHAR(255)
) engine InnoDB;
select * from user where id = 5000;
+------+------+---------------+
| id | type | name |
+------+------+---------------+
| 5000 | 0 | usr_name_5000 |
+------+------+---------------+
0.00401250
◾️1件UPDATE
update user set name = 'name_500001' where id = 5001;
0.01640200
◾️1件DELETE
delete from user where id = 5002;
0.00935400
MySQL8.0 MyISAM
create table user(
id INT,
type INT,
name VARCHAR(255)
) engine MyISAM;
select * from user where id = 5000;
+------+------+---------------+
| id | type | name |
+------+------+---------------+
| 5000 | 0 | usr_name_5000 |
+------+------+---------------+
0.07204400
◾️1件UPDATE
update user set name = 'name_500001' where id = 5001;
0.02672875
◾️1件DELETE
delete from user where id = 5002;
0.02560125
MySQL8.0 InnoDB
create table user(
id INT,
type INT,
name VARCHAR(255)
) engine InnoDB;
select * from user where id = 5000;
+------+------+---------------+
| id | type | name |
+------+------+---------------+
| 5000 | 0 | usr_name_5000 |
+------+------+---------------+
0.00575250
◾️1件UPDATE
update user set name = 'name_500001' where id = 5001;
0.01512700
create table user(
id INT AUTO_INCREMENT,
type INT,
name VARCHAR(255),
PRIMARY KEY (id)
);
create table user_score(
id INT AUTO_INCREMENT,
user_id INT,
score INT,
PRIMARY KEY (id), index(user_id)
);
◾️プロシージャ作成
次は、テストデータはプロシージャーで作成しますのでプロシージャを作成します。
以下の通りデータ作成してくれるようになっています。
user.type:カウントを2で割った余りを格納(あまり意味がないカラムです。)
user.name:「user_name_{カウント}」の値を格納
user.score:ランダムな数値を格納
-- 区切り文字を「//」に変更する
DELIMITER //
-- make_sample_dataというテストデータ作成用プロシージャーを作成する
create procedure make_sample_data(in i int)
begin
declare count int default 0;
-- 繰り返し
while count < i do
set count = count + 1;
INSERT INTO user (type, name) VALUES(MOD(count,2),CONCAT('usr_name_',count));
INSERT INTO user_score (user_id, score) VALUES(count, CEIL(RAND() * 1000));
INSERT INTO user_score (user_id, score) VALUES(count, CEIL(RAND() * 1000));
INSERT INTO user_score (user_id, score) VALUES(count, CEIL(RAND() * 1000));
end while;
end
//
-- 区切り文字を「;」に戻す
DELIMITER ;
select max(score_sum.sum) as max from (
SELECT
`user_id`,
SUM(`score`) AS `sum`
FROM
`user_score`
GROUP BY
`user_id`
) AS `score_sum`
;
// 実行結果
+------+
| max |
+------+
| 2998 |
+------+
1 row in set (10.51 sec)
サブクエリを使うことで高速化が測れる場合
サブクエリ内でデータの絞り込みが行える場合、使用するとクエリの高速化ができます。
上記で準備したテーブルで、ユーザのスコアの平均が990のデータを絞り込む例で考えてみます。
◾️サブクエリを取得した場合
SELECT
`user`.*,
`score`.`average`
FROM
(
SELECT
`user_id`,
AVG(`score`) AS `average`
FROM
`user_score`
GROUP BY
`user_id`
HAVING `average` > 990
) AS `score`
JOIN
`user`
ON `user`.`id` = `score`.`user_id`
;
// 実行結果
59 rows in set (8.75 sec)
◾️JOINを使用した場合
SELECT
`user`.*,
AVG(`user_score`.`score`) AS `average`
FROM
`user`
LEFT JOIN
`user_score`
ON `user`.`id` = `user_score`.`user_id`
GROUP BY
`user_id`
HAVING `average` > 990
;