PostgreSQL 入門

PostgreSQL 文字データ型

PostgreSQLを含むあらゆるリレーショナルデータベースにおいて、テキスト情報の保存と管理は、大多数のアプリケーションにおける基盤となるタスクです。ユーザー名や製品の説明から、記事のコンテンツや住所に至るまで、テキストデータはいたる所に存在します。文字列に適切なデータ型を選択することは、データベースのパフォーマンス、ストレージ効率、およびデータ整合性(Integrity)において極めて重要です。

本章では、PostgreSQLで使用可能な主要な文字データ型である CHARVARCHAR、および TEXT について深く掘り下げます。それぞれの違い、使用パターン、および潜在的な影響を理解することで、データベースのテーブル設計時に賢明な意思決定を行い、テキストデータが効率的かつ適切に保存されることを保証できるようになります。

1. CHAR (固定長文字列) の理解

CHAR(n) データ型は、固定長の文字列を保存するために使用されます。カラムを CHAR(10) と宣言すると、常に正確に10文字分のスペースを占有します。

  • 不足分のパディング: 挿入した文字列が10文字より短い場合、PostgreSQLは指定された長さに達するまで文字列の末尾にスペースをパディング(埋め合わせ)します。
  • 超過時の動作: 10文字を超える文字列を挿入しようとした場合、超過分がすべてスペースであれば、PostgreSQLはそれらを静かに切り捨てて10文字として保存します。しかし、超過分にスペース以外の文字が含まれている場合は、通常エラーが発生します(これは現代のPostgreSQLにおけるデフォルトの安全な動作です)。

CHARの大きな特徴はその固定長にあります。ストレージサイズが予測可能であるため、比較操作の処理速度がわずかに速くなる場合があります。しかし、データの長さが頻繁に変わり、その多くが宣言された最大長よりも短い場合、CHARを使用すると深刻なストレージスペースの浪費につながります。

1.1 構文と例

CHARの構文は非常にシンプルです。

column_name CHAR(n)

ここで n は整数であり、保存する正確な文字数を表します。

例 1:2文字の州・省の略称を保存する

アメリカの州名の略称を保存する必要があると仮定します。これらは常に正確に2文字です(例:'CA'、'NY'、'TX')。この場合、CHAR(2) は最適な選択です。

CREATE TABLE customers (
    customer_id SERIAL PRIMARY KEY,
    customer_name VARCHAR(100),
    state_abbreviation CHAR(2) -- 常に2文字であることを強制
);

INSERT INTO customers (customer_name, state_abbreviation) VALUES
('Alice Smith', 'CA'),
('Bob Johnson', 'NY'),
('Charlie Brown', 'TX');

-- 保存された値と長さを確認するためのクエリ
SELECT customer_name, state_abbreviation, LENGTH(state_abbreviation) FROM customers;

この例では、state_abbreviation は常に2文字分のスペースを占有します。もし1文字だけの 'C' を挿入しようとすると、データベース内部ではスペースがパディングされ 'C ' として保存されます。

実際のユースケース例:固定長の製品SKU

多くの在庫管理システムでは、固定長の在庫管理単位(SKU)コードを使用します。企業が標準の8文字SKU(例:'PG001234'、'ELX98765')を使用している場合、CHAR(8) が適しています。

CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    product_name VARCHAR(255),
    sku CHAR(8) UNIQUE -- SKUを一意にし、かつ8文字固定に強制
);

INSERT INTO products (product_name, sku) VALUES
('PostgreSQL マグカップ', 'PG000001'),
('ゾウのぬいぐるみ', 'EL000001');

-- 自動パディングをデモンストレーションするために短い文字列を挿入してみます:
INSERT INTO products (product_name, sku) VALUES ('短SKUの商品', 'SHORT');

-- 'SHORT' は5文字しかないため、末尾に3つのスペースがパディングされ 'SHORT   ' になります
SELECT product_name, sku, LENGTH(sku) FROM products WHERE product_name = '短SKUの商品';
-- 入力は 'SHORT' ですが、LENGTH(sku) は 8 を返すことがわかります

2. VARCHAR (可変長文字列) の理解

VARCHAR(n) データ型は、ユーザーが定義した最大長さの制限を持つ可変長文字列(Variable-Character)を保存するために使用されます。

CHARとは異なり、VARCHARは文字列にスペースをパディングしません。実際に提供された文字列のみを保存し、それに加えて実際の文字列長を記録するためのわずかなオーバーヘッド(通常は1〜4バイト)を消費します。これにより、VARCHARは長さが著しく変化するテキストを保存する際に、ストレージ効率が非常に高くなります。

指定された n を超える長さの文字列を挿入しようとすると、PostgreSQLはエラーをスローし、挿入を拒否します。デフォルトでは、VARCHARは最大長さの制限を厳格に適用します。

2.1 構文と例

VARCHARの構文は以下の通りです。

column_name VARCHAR(n)

ここで n は整数であり、許可される最大文字数を表します。

例 1:顧客名を保存する

顧客名の長さは人によって大きく異なります。VARCHAR(100) を使用すれば、名前を最大100文字まで許可しつつ、各名前が実際に必要とするスペースのみを消費します。

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE, -- ユーザー名は最大50文字
    email VARCHAR(255) NOT NULL, -- メールアドレスは最大255文字
    bio VARCHAR(500)             -- 自己紹介は最大500文字
);

INSERT INTO users (username, email, bio) VALUES
('johndoe', '[email protected]', '熱狂的なデータベース愛好家です。'),
('alice_wonder', '[email protected]', 'PostgreSQLの基礎を学習中です。');

-- 50文字を超えるユーザー名を挿入しようとすると、エラーが発生します:
-- INSERT INTO users (username, email) VALUES ('this_is_a_really_long_username_for_my_test_account_that_should_fail', '[email protected]');
-- エラーメッセージ: value too long for type character varying(50)

SELECT username, email, LENGTH(username), LENGTH(email) FROM users;

注意点として、LENGTH(username) が返すのは、宣言された最大長50ではなく、文字列の実際の長さです。

実際のユースケース例:製品の短い説明

ECサイトでは製品の説明を保存する必要があります。妥当な上限の長さが存在する場合(例:1000文字など)、VARCHAR(1000) は良い選択肢となります。

CREATE TABLE products_ecommerce (
    product_id SERIAL PRIMARY KEY,
    product_name VARCHAR(255) NOT NULL,
    short_description VARCHAR(1000), -- 最大1000文字
    price DECIMAL(10, 2)
);

3. TEXT (無制限テキスト) の理解

TEXT データ型は、任意の長さの可変長文字列を保存するために使用されます。

PostgreSQLにおいて、TEXTは本質的に「明示的な長さ制限のないVARCHAR」です。PostgreSQLはTEXTデータを非常に効率的に保存します。VARCHARと同様に、実際の文字列コンテンツが必要とするスペースのみを消費し、それに加えてごくわずかな長さ記録用のオーバーヘッドが加わります。

PostgreSQLの内部では、長さを指定しないVARCHAR(単に VARCHAR と記述)とTEXTの間には実質的な機能の違いはありません。しかし、コードの可読性や「このテキストには長さの制限がない」という意図を明確にするために、データベースレイヤーで長さの上限を強制したくない場合は、通常TEXTが好まれます。

3.1 構文と例

TEXTの構文は非常にシンプルで、引数は必要ありません。

column_name TEXT

例 1:記事のコンテンツを保存する

ブログ記事、ニュース、またはレビューなどは、長さが数文字から数万文字まで及ぶ可能性があるため、TEXTが最適な選択です。

CREATE TABLE articles (
    article_id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    author VARCHAR(100),
    content TEXT, -- 記事全文。非常に長くなる可能性がある
    published_date TIMESTAMP DEFAULT NOW()
);

INSERT INTO articles (title, author, content) VALUES
('AI時代のデータベースの未来', 'Evelyn Reed博士', '人工知能があらゆる業界を変革している現代において、データベースはAIモデルが必要とする膨大なデータの保存、管理、検索において重要な役割を果たしています。本記事では、進化し続けるデータベース技術の展望について探ります...');

SELECT title, LENGTH(content) AS content_length FROM articles;

実際のユースケース例:法務文書の保存

法律事務所では、契約書や免責事項の全文を直接データベースに保存する必要があるかもしれません。これらの文書は極めて長文になるため、TEXTが唯一の実用的な選択肢となります。

4. 核心的な比較:どの型をいつ使うべきか?

CHAR、VARCHAR、またはTEXTのどれを選択するかは、保存するデータの具体的な特徴に依存します。以下にそれらのまとめと推奨されるユースケースを示します。

特性CHAR(n)VARCHAR(n)TEXT
長さのタイプ固定長 (Fixed-length)最大制限付きの可変長制限なしの可変長
スペースのパディングn文字に達するまでスペースを埋めるパディングしないパディングしない
ストレージオーバーヘッド常に n文字分のスペースを占有実際の長さ + 1〜4バイト実際の長さ + 1〜4バイト
超過時の挙動nを超え、かつスペース以外ならエラーnを超えるとエラー長さによるエラーは発生しない
最適なユースケース短く、固定長が既知のコード (例: 'M'/'F', 'JP', 郵便番号)名前、住所、タイトル、メール、制限のある短い説明長文の記事、レビュー、大規模なJSON/XML、法務文書

4.1 詳細な選択ガイド

いつ CHAR(n) を使うべきか:

  • データが絶対的かつ、常に既知の固定長である場合。
  • 例:2文字の国コード、1文字のフラグ('Y'/'N')、特定の固定長の識別コード。
  • 注意:スペースのパディング動作が十分に理解されていないと予期せぬ結果を招くことがあるため、現代の一般的なテキスト保存では使用機会が減っています。

いつ VARCHAR(n) を使うべきか:

  • 長さが変化する文字列を保存する必要があるが、同時にデータベースレイヤーで妥当な長さの上限を設定したい場合。
  • 例:ユーザー名(悪意のある入力を防ぐための50文字制限)、メールアドレス、記事のタイトル。これは大多数のテキストカラムにおけるデフォルトかつ推奨の選択です。異常に巨大なデータや誤った入力がシステムリソースを占有するのを防ぐことができます。

いつ TEXT を使うべきか:

  • 長さが変化する文字列を保存する必要があり、かつ実質的な長さの上限がない、あるいはデータベース側で制限をかけたくない場合。
  • 例:ブログの本文、詳細な製品説明、ユーザーのコメントやフィードバック。PostgreSQLでは、可変長文字列の保存と処理において、VARCHARと同じくらい高い効率を誇ります。

エンコーディングに関する注意点:

PostgreSQLは様々な文字セットをサポートしていますが、推奨されるデフォルト設定は UTF-8 です。日本語や中国語などのマルチバイト文字を処理する場合、実際に占有されるバイト数は文字数よりも大きくなる可能性があります(例:UTF-8では、1つの日本語文字は通常3バイトを占有します)。CHAR(n) および VARCHAR(n) における n文字数 を指し、バイト数ではありません。PostgreSQLは低レイヤーで文字からバイトへの変換を自動的に処理します。