メニューを閉じる

テクノデジタルグループ

メニューを開く

2025.06.19

DB

クエリ最適化だけで満足していませんか?SQLパフォーマンスチューニングの新視点

SQLパフォーマンスチューニングの新視点:

SQLのパフォーマンスチューニングと聞くと、多くのエンジニアは「インデックスの追加」「JOINの見直し」「EXPLAINによる分析」といった手法を思い浮かべるでしょう。しかし、それだけで十分でしょうか?

実は、SQLのパフォーマンスを向上させるためには、クエリの書き方だけでなく、データベースの設計やアプリケーションとの連携も深く考慮する必要があります。本記事では、従来のアプローチとは異なる視点から、SQLパフォーマンスチューニングの重要なポイントを掘り下げます。


1. データモデルの見直し:正規化 vs. 非正規化

「正規化してスリムなテーブル設計をするのが正義」だと思っていませんか? もちろん、データの整合性を保つために正規化は重要です。しかし、極端に正規化しすぎると、データ取得時に複雑なJOINが発生し、パフォーマンスが低下することもあります。

【具体例】

例えば、以下のような2つのテーブルがあるとします。

-- ユーザー情報テーブル
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

-- ユーザーの注文情報テーブル
CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    product_name VARCHAR(100),
    price DECIMAL(10,2),
    FOREIGN KEY (user_id) REFERENCES users(id)
);


この設計では、ユーザーの注文履歴を取得する際にJOINを使う必要があります。

SELECT users.name, orders.product_name, orders.price 
FROM users 
JOIN orders ON users.id = orders.user_id;

  
この方法はデータの一貫性を保ちやすい一方で、大量のデータがあるとJOINによる負荷が増えます。

そこで、非正規化の手法を用い、よく使う情報をあらかじめ格納した「キャッシュテーブル」を作成することで、クエリの負担を軽減できます。

CREATE TABLE user_order_summary (
    user_id INT PRIMARY KEY,
    name VARCHAR(50),
    last_order_product VARCHAR(100),
    total_spent DECIMAL(10,2)
);


このテーブルを適宜更新することで、シンプルなSELECT文で高速にデータ取得が可能になります。

SELECT * FROM user_order_summary WHERE user_id = 1;

2. アプリケーションレイヤーのキャッシュを活用する

SQLをチューニングするだけでなく、そもそもSQLを実行する回数を減らすことも重要です。

【キャッシュの活用】

たとえば、RedisMemcachedといったインメモリキャッシュを使うことで、同じデータを何度もDBに問い合わせる負担を減らせます。

Python + Redis の例:

import redis
import pymysql

# Redisに接続
cache = redis.Redis(host='localhost', port=6379, db=0)

# キャッシュから取得
user_id = 1
cached_data = cache.get(f'user:{user_id}')

if cached_data:
    print("Cache Hit!", cached_data)
else:
    # データベース接続
    conn = pymysql.connect(host='localhost', user='root', password='', db='test')
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
    user_data = cursor.fetchone()
    
    # キャッシュに保存
    cache.set(f'user:{user_id}', user_data, ex=3600)  # 1時間キャッシュ
    print("Cache Miss!", user_data)


こうすることで、頻繁にアクセスされるデータはDBを経由せず、高速に取得できます。


3. バッチ処理の最適化

大量データを一括処理するとき、トランザクション管理バッチ処理の分割がカギになります。

【適切なバッチ処理】

NG例: 10万件のデータを1つずつINSERTする

INSERT INTO logs (message, created_at) VALUES ('log1', NOW());
INSERT INTO logs (message, created_at) VALUES ('log2', NOW());
... 10万回繰り返し ...


OK例: バルクインサートを使う

INSERT INTO logs (message, created_at) VALUES
    ('log1', NOW()),
    ('log2', NOW()),
    ('log3', NOW());


また、バッチ処理を分割することでデータベースの負荷を分散できます。

SELECT * FROM logs WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31';

4. データベース設定の最適化

DBの設定を見直すだけで劇的に速くなることもあります!

例えば、MySQLのinnodb_buffer_pool_sizeを適切に設定するだけで、ディスクI/Oの削減が可能です。

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SET GLOBAL innodb_buffer_pool_size = 2G;


PostgreSQLでは、work_memを調整すると、ORDER BYやJOINのパフォーマンスが向上します。

SHOW work_mem;
SET work_mem = '64MB';

5. 実際のアクセスパターンを考慮する
「開発環境で速いから本番でも問題ない」と思い込んでいませんか?

SQLチューニングを行う際は、実際の本番環境のデータ量やアクセスパターンを考慮することが不可欠です。開発環境で数千件のデータしかない状態でテストし、本番環境の数百万件のデータで問題が発生するケースは珍しくありません。

プロファイリングツール(MySQLなら`slow_query_log`、PostgreSQLなら`pg_stat_statements`など)を活用し、本番環境のクエリパフォーマンスを定期的にチェックすることが重要です。

スロークエリログを有効にする(MySQL)

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1; -- 1秒以上のクエリを記録

まとめ

SQLのパフォーマンスチューニングは、単にクエリを改善するだけではなく、データモデル、キャッシュ、バッチ処理、データベース設定、アクセスパターンなど、多角的に考える必要があります。
また、高速化はデータ整合性とトレードオフの関係だったりもします。
「SQLが遅い=クエリの問題」と決めつけず、広い視野で適切な改善策を考えてみる必要がありそうですね。


参考文献

正規化 vs. 非正規化

https://clickhouse.com/docs/jp/data-modeling/denormalization

アプリケーションレイヤーのキャッシュを活用する

https://www.wallarm.com/jp/cloud-native-products-101/redis-vs-memcached-in-memory-data-store

バッチ処理の最適化

https://medium.com/nazar-io/sql-performance-killers-individual-inserts-vs-bulk-inserts-14176c201673

データベース設定の最適化

https://releem.com/docs/mysql-performance-tuning/innodb_buffer_pool_size

実際のアクセスパターンを考慮する

https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html

https://www.crunchydata.com/blog/tentative-smarter-query-optimization-in-postgres-starts-with-pg_stat_statements


【記事への感想募集中!】

記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!
  • こんな記事が読んでみたい、こんなことが知りたい、調べてほしい!という意見も募集中!
  • いただいた感想は今後の記事に活かしたいと思います!

感想フォームはこちら


【テクノデジタルではエンジニア/デザイナーを積極採用中です!】

下記項目に1つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事