Day2 後半のゴール
「実際にテーブルを作りながら、“型・AUTO_INCREMENT・InnoDB”を体で覚える」
前半で、
VARCHAR / DATETIME / AUTO_INCREMENT の意味を頭で理解しました。
後半では、
実際にテーブルを作って INSERT / SELECT してみる
「型を変えると何が変わるか」を体で感じる
MySQL特有の「エンジン(InnoDB)」という概念を押さえる
ここまで行きます。
SQLite経験者として、「ここが違うんだな」をハッキリさせる時間です。
例題テーブル1:ユーザー+ログイン履歴
「VARCHAR / DATETIME / AUTO_INCREMENT を全部使うミニ例」
まずは、よくある「ユーザー+ログイン履歴」のテーブルを作ってみます。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL
) ENGINE=InnoDB;
CREATE TABLE login_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
logged_in_at DATETIME NOT NULL,
ip_address VARCHAR(45) NOT NULL
) ENGINE=InnoDB;
SQLここで意識してほしいポイントは3つです。
INT AUTO_INCREMENT PRIMARY KEY
→ IDは自動採番。自分で数えない。
VARCHAR(50) / VARCHAR(255) / VARCHAR(45)
→ 項目ごとに「現実の長さ」を意識している。
IPアドレスはIPv6も考えて45文字にしている例。
DATETIME
→ 作成日時・ログイン日時を“時間として”扱う前提。
そして、最後の ENGINE=InnoDB。
これが「エンジン」の指定です。
今は「MySQLでは基本 InnoDB を使う」とだけ覚えておけばOKです。
実際にデータを入れてみる
「AUTO_INCREMENT と DATETIME の動きを確認する」
ユーザーを2人、ログイン履歴を数件入れてみます。
INSERT INTO users (name, email, created_at)
VALUES
('山田太郎', 'taro@example.com', NOW()),
('佐藤花子', 'hanako@example.com', NOW());
INSERT INTO login_logs (user_id, logged_in_at, ip_address)
VALUES
(1, NOW(), '192.168.0.10'),
(1, NOW(), '192.168.0.11'),
(2, NOW(), '192.168.0.12');
SQLここで重要なのは、
id を一切指定していないのに、自動で 1,2,3… が入るNOW() で「現在時刻」が DATETIME として入る
という2点です。
確認してみます。
SELECT * FROM users;
SELECT * FROM login_logs;
SQLid が連番になっていて、created_at / logged_in_at に
ちゃんと日時が入っていればOKです。
SQLiteのときは「なんとなくTEXTで日時を入れていた」のが、
MySQLでは「DATETIME+NOW()」で“時間として扱う”形に変わっています。
DATETIME を使うと何がうれしいか
「“日付だけ”や“期間”での絞り込みが自然になる」
例えば、「2025年5月にログインした履歴だけ欲しい」とします。
SELECT *
FROM login_logs
WHERE logged_in_at >= '2025-05-01 00:00:00'
AND logged_in_at < '2025-06-01 00:00:00';
SQLこれは TEXT でも書けますが、DATETIME ならさらに、
SELECT
DATE(logged_in_at) AS login_date,
COUNT(*) AS login_count
FROM login_logs
GROUP BY DATE(logged_in_at)
ORDER BY login_date;
SQLのように、「日別ログイン回数」を簡単に出せます。
ここで感じてほしいのは、
「DATETIME にしておくと、“時間として”の操作が自然に書ける」
ということです。
TEXT で持っていると、「文字列としての比較」に頼ることになり、
型としての恩恵を受けにくくなります。
例題テーブル2:商品+注文
「AUTO_INCREMENT と VARCHAR の“設計の意味”をもう一度確認する」
次は、EC風の超シンプル版を作ります。
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price INT NOT NULL
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
quantity INT NOT NULL,
ordered_at DATETIME NOT NULL
) ENGINE=InnoDB;
SQLここでのポイントは、
商品名は VARCHAR(100)
→ 「そんなに長くないけど、そこそこ長いかも」という現実を反映
価格は INT
→ 小数が要らない前提なら INT で十分
注文ID・商品IDはすべて AUTO_INCREMENT の INT
→ 「内部用のID」として連番を使う
という設計の意図です。
SQLite だと「全部 INTEGER / TEXT でいいか」となりがちですが、
MySQLでは「何が文字列で、何が数値で、何がIDか」をはっきり分けます。
エンジン(InnoDB)とは何か
「“テーブルの中身をどう保存・管理するか”を決める仕組み」
ここで、MySQL特有の概念「エンジン」に触れます。
テーブル定義の最後に書いた ENGINE=InnoDB。
これは、
「このテーブルは InnoDB というエンジンで管理してください」
という指定です。
エンジンとは、
データをどう保存するか
トランザクションをどう扱うか
ロック(同時更新)をどう制御するか
といった“中身の仕組み”を決めるモジュールです。
SQLite では、エンジンを選ぶ概念はありませんでした。
MySQLでは、代表的なエンジンとして InnoDB / MyISAM などがありますが、
今は「基本 InnoDB 一択」と思っておいてOKです。
なぜ InnoDB を使うのか
「トランザクション・外部キー・安全性の“標準装備”だから」
InnoDB を選ぶ理由は、ざっくり言うとこうです。
トランザクションが使える
→ 複数のINSERT/UPDATEを「全部成功か全部失敗」にできる
外部キー制約が使える
→ 親テーブルにないIDを子テーブルに入れようとするとエラーになる
クラッシュ時の復旧が強い
→ サーバーが落ちても、データの整合性を保ちやすい
SQLite でもトランザクションはありましたが、
MySQL+InnoDB は「サーバー前提の本格運用」に耐えるように作られています。
Day2 の段階では、
「MySQLでは、テーブルの“中身の仕組み”として InnoDB を指定する」
「InnoDB はトランザクションと外部キーが使える“ちゃんとしたやつ”」
くらいの理解で十分です。
エンジンを意識したテーブル定義
「ENGINE=InnoDB を“おまじない”で終わらせない」
さっきの products と orders に、
外部キー制約を付けてみます。
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price INT NOT NULL
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
quantity INT NOT NULL,
ordered_at DATETIME NOT NULL,
CONSTRAINT fk_orders_product
FOREIGN KEY (product_id)
REFERENCES products(id)
) ENGINE=InnoDB;
SQLここでのポイントは、
FOREIGN KEY (product_id) REFERENCES products(id)
→ orders.product_id は、必ず products.id に存在する値でなければならない
というルールを、DB側に持たせていることです。
この「外部キー制約」が使えるのは、InnoDB の大きなメリットです。
SQLiteでも外部キーはありましたが、
MySQLでは「エンジンによって使える/使えない」が変わるので、
InnoDBを選ぶ意味がよりハッキリしています。
SQLite経験者が InnoDB で得をするポイント
「“アプリで頑張る”から“DBに任せる”へ」
SQLite では、
外部キーを使わずに「アプリ側でチェックする」ことも多かったと思います。
MySQL+InnoDB では、
外部キーで「ありえないデータ」をDB側でブロックできる
トランザクションで「途中まで書かれた中途半端な状態」を防げる
というメリットがあります。
これはセキュリティ的にも重要で、
不正なリクエストやバグがあっても、
DB側が「そのデータはおかしい」と弾いてくれる
という“最後の砦”になります。
Day2 の時点では、
「InnoDB を使うと、DBがデータの整合性を守るのを手伝ってくれる」
とイメージしておけば十分です。
Day2 後半のまとめ
VARCHAR / DATETIME / AUTO_INCREMENT を実際のテーブル(users, login_logs, products, orders)で使ってみると、「型をちゃんと決める」「IDは自動採番に任せる」「日時はDATETIME+NOW()で扱う」という MySQL流の設計が体感できる。
DATETIME にしておくと、DATE(カラム) で日付だけ取り出したり、期間指定や日別集計を自然に書けるようになり、「文字列としての日時」ではなく「時間としての日時」を扱う感覚が身につく。
AUTO_INCREMENT を使った INT の主キーは、「内部用の連番ID」として機能し、メールアドレスや会員番号など“意味のある値”を主キーにしない設計に導いてくれる。これはセキュリティと将来の仕様変更に強い。ENGINE=InnoDB は「このテーブルは InnoDB というエンジンで管理する」という指定で、トランザクション・外部キー・クラッシュ耐性など、本番運用に必要な機能を標準装備してくれる。
SQLite経験者にとっての一番の差分は、「型をきっちり決める」「IDはAUTO_INCREMENT」「エンジン(InnoDB)を前提に設計する」という3点であり、ここを押さえると MySQL を“なんとなくSQLiteの延長”ではなく、“サーバーDBとしてちゃんと使う”モードに切り替えられる。
この感覚が入ったら、
Day3以降で「インデックス」「クエリ最適化」「権限設計」に進んでも、
迷子になりにくくなります。
