😺
大規模データを効率処理する方法:Pythonで使えるデータベース比較
はじめに
最初はCSVをpandasで直接扱うだけで十分ですが、データが数十万行を超えると処理が重くなり、共有も難しくなります。こうした課題を解決する方法がデータベースへの登録です。必要な部分だけ抽出でき、検索や集計も高速化されます。この記事では、Pythonから使える代表的なDBの特徴とメリット・デメリットを整理します。
DBに登録して扱うメリット
以前の記事ではテーブルデータをそのままデータフレームで扱ってきましたが、 データ量が増えると次のような課題が出てきます。
- メモリに載りきらない大規模データは処理が重くなる
- 毎回CSVを読み直すと処理が遅い
- 複数人でデータを共有するのが難しい
こうした場合には、SQLiteなどのデータベースに一度登録してから 、SQLで必要な部分だけを取り出す方法が有効です。DBを使うメリットは以下の通りです。
- 大規模データに対応:必要な部分だけ抽出してメモリ節約 できる
- 検索・集計が高速:インデックスやSQL文を活用できる
- データの永続化・再利用:前処理済みデータを保存して再利用できる
- 共有・拡張性:PostgreSQLやMySQLにすれば複数人で利用できる
分析フェーズではpandasの方が手軽ですが、「中長期的にデータを蓄積して分析する」場面ではDBの利用を検討する価値があります。
Pythonから構築・利用できるDB
SQLite
-
特徴
- Python標準ライブラリ(sqlite3)で扱える
- 1つのファイルにすべてのデータを格納する
-
メリット
- インストール不要(Pythonに同梱)
- 高速・単一ファイル形式なので軽量
- 小規模~中規模データの保存・分析に最適
-
デメリット
- 同時アクセス(並行処理)に弱い
- 大規模トランザクション処理には不向き
コーディング例
# 標準ライブラリのためpip不要
import sqlite3
db_path = "example.sqlite"
conn = sqlite3.connect(db_path)
cur = conn.cursor()
# スキーマ作成
cur.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL
)
""")
# CREATE
cur.execute("INSERT INTO items (name, price) VALUES (?, ?)", ("apple", 120.5))
conn.commit()
# READ
cur.execute("SELECT id, name, price FROM items WHERE name = ?", ("apple",))
print(cur.fetchall())
# UPDATE
cur.execute("UPDATE items SET price = ? WHERE name = ?", (150.0, "apple"))
conn.commit()
# DELETE
cur.execute("DELETE FROM items WHERE name = ?", ("apple",))
conn.commit()
cur.close()
conn.close()
MySQL
-
特徴
- mysqlclientやsqlalchemyで利用可能
- 世界的に広く使われているRDB
-
メリット
- レプリケーションや分散処理に対応している
- Webサービスでの利用実績が豊富
-
デメリット
- PostgreSQLより機能面で制約がある部分もある
- 設定や運用にDB知識が必要
コーディング例
# pip install pymysql
import pymysql
conn = pymysql.connect(
host="localhost", port=3306,
user="root", password="password",
database="testdb", autocommit=True
)
cur = conn.cursor()
# スキーマ作成
cur.execute("""
CREATE TABLE IF NOT EXISTS items (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DOUBLE NOT NULL
)
""")
# CREATE
cur.execute("INSERT INTO items (name, price) VALUES (%s, %s)", ("apple", 120.5))
# READ
cur.execute("SELECT id, name, price FROM items WHERE name = %s", ("apple",))
print(cur.fetchall())
# UPDATE
cur.execute("UPDATE items SET price = %s WHERE name = %s", (150.0, "apple"))
# DELETE
cur.execute("DELETE FROM items WHERE name = %s", ("apple",))
cur.close()
conn.close()
PostgreSQL
-
特徴
- psycopg2やsqlalchemyで利用可能
- オープンソースの高機能RDB
-
メリット
- トランザクション・インデックス・集計機能が強力
- JSONや全文検索など拡張性が高い
- 大規模・複雑なシステムでも安定稼働
-
デメリット
- インストールや設定が必要
- SQLiteより学習コストが高め
コーディング例
# pip install psycopg2-binary
import psycopg2
conn = psycopg2.connect(
host="localhost", port=5432,
user="postgres", password="password",
dbname="testdb"
)
cur = conn.cursor()
# スキーマ作成
cur.execute("""
CREATE TABLE IF NOT EXISTS items (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price DOUBLE PRECISION NOT NULL
)
""")
conn.commit()
# CREATE
cur.execute("INSERT INTO items (name, price) VALUES (%s, %s)", ("apple", 120.5))
conn.commit()
# READ
cur.execute("SELECT id, name, price FROM items WHERE name = %s", ("apple",))
print(cur.fetchall())
# UPDATE
cur.execute("UPDATE items SET price = %s WHERE name = %s", (150.0, "apple"))
conn.commit()
# DELETE
cur.execute("DELETE FROM items WHERE name = %s", ("apple",))
conn.commit()
cur.close()
conn.close()
DuckDB
-
特徴
- Pythonからduckdbライブラリで利用
- 「SQLiteの分析特化版」とも呼ばれる組み込みDB
-
メリット
- SQLでデータフレームやParquetやCSVを直接クエリ可能
- 列指向DBなので分析処理が非常に高速
- SQLite同様にデータをファイルベースで軽量に扱える
-
デメリット
- まだ新しく利用実績は比較的少ない
- 同時アクセスやトランザクション処理は弱め
コーディング例
# pip install duckdb
import duckdb
# ファイル永続化する場合は 'example.duckdb' を指定、:memory: ならメモリDB
conn = duckdb.connect("example.duckdb")
# スキーマ作成
conn.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER,
name TEXT,
price DOUBLE
)
""")
# CREATE
conn.execute("INSERT INTO items (id, name, price) VALUES (?, ?, ?)", (1, "apple", 120.5))
# READ
print(conn.execute("SELECT id, name, price FROM items WHERE name = ?", ("apple",)).fetchall())
# UPDATE
conn.execute("UPDATE items SET price = ? WHERE name = ?", (150.0, "apple"))
# DELETE
conn.execute("DELETE FROM items WHERE name = ?", ("apple",))
conn.close()
MongoDB
-
特徴
- Pythonからはpymongoで利用
- ドキュメント指向のNoSQL DBで、JSONに近い形式でデータを保存
-
メリット
- JSONライクな柔軟なデータ構造
- データ項目を事前に固定しなくても良い(データ構造が頻繁に変わる場合に特に便利)
- 項目数の増加に強い
-
デメリット
- 複雑なJOINはできない
- データ整合性(ACID)はRDBより弱い
コーディング例
# pip install pymongo
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017/")
db = client["testdb"]
col = db["items"]
# CREATE(_id は自動付与。RDBのid相当を自分で入れてもOK)
col.insert_one({"name": "apple", "price": 120.5})
# READ
doc = col.find_one({"name": "apple"})
print(doc)
# UPDATE(最初に一致した1件を更新)
col.update_one({"name": "apple"}, {"$set": {"price": 150.0}})
# DELETE(該当1件削除)
col.delete_one({"name": "apple"})
client.close()
Redis
-
特徴
- Pythonからはredis-pyで利用
- インメモリ型のKey-Valueストア
-
メリット
- メモリ上で処理するため非常に高速(キャッシュ用途に最適)
- pub/sub(通知)、セッション管理などに強い
-
デメリット
- 永続化は補助的(ディスク保存も可能だがメインはメモリ)
- 大量データを長期保存する用途には不向き
コーディング例
# pip install redis
import redis
import json
r = redis.Redis(host="localhost", port=6379, db=0)
# キーを "item:{id}" として表現、値はHashまたはJSON文字列を利用
key = "item:1"
# CREATE(Hash)
r.hset(key, mapping={"name": "apple", "price": "120.5"})
# READ
print(r.hgetall(key)) # b'name': b'apple', b'price': b'120.5'
# UPDATE(Hashのフィールド更新)
r.hset(key, "price", "150.0")
# DELETE(キーごと削除)
r.delete(key)
# JSONで保持したい場合(RedisJSONがない前提で文字列化)
key_json = "itemjson:1"
r.set(key_json, json.dumps({"name": "apple", "price": 120.5})) # CREATE
print(json.loads(r.get(key_json))) # READ
r.set(key_json, json.dumps({"name": "apple", "price": 150.0})) # UPDATE(丸ごと上書き)
r.delete(key_json) # DELETE
おわりに
大規模データを効率的に扱うには、DBの活用が有効です。
- 個人利用や小規模データ:SQLite・DuckDB
- チームや大規模データを扱う業務システム:PostgreSQL・MySQL
- 柔軟なデータ構造やキャッシュ用途:MongoDB・Redis
pandasの手軽さを活かしつつ、データ規模や用途に応じてDBを選ぶのがおすすめです。
Discussion