MySQL | SQLite経験者向け、30日で習得するMySQL:差分理解 - Day2 SQLiteとの違い

SQL MySQL
スポンサーリンク

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;
SQL

id が連番になっていて、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 を“おまじない”で終わらせない」

さっきの productsorders に、
外部キー制約を付けてみます。

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以降で「インデックス」「クエリ最適化」「権限設計」に進んでも、
迷子になりにくくなります。

タイトルとURLをコピーしました