TT Lab
はじめる
学ぶ 学習パス コース

SIのDB運用

なぜカラム名から決めるのか

TT Labで続きを見る

一言でいうと

カラム名を先に決める理由は見た目の美しさではありません。標準がないと、同じ意味のカラムが名前も長さも違う形で3つできてしまい、その代償を3年後の移行で払うことになるからです。

なぜこれが問題なのか

標準がなくても、開発はうまく回ります。各チームがそれぞれ合理的に名前を付けるからです。問題は、その3つを統合するときに初めて表面化します。統合照会画面、精算の突合、そして次世代システムへの移行です。

いちばん痛手になるのは長さです。顧客名をある所では50文字、別の所では30文字で定義していると、長い名前が入ってくる日に、黙って切り詰められたままロードされます。エラーが出ないので誰も気づかず、数か月後に「この顧客の名前がなぜこうなっているのか」という問い合わせで発覚します。

3年後に起きること

プロジェクトの初期にデータ標準を決めないと、こうなります。

고객관리 팀:  CUSTOMER   (CUST_NAME    VARCHAR(50))
주문 팀:      ORDERS     (CUSTOMER_NM  VARCHAR(100))
정산 팀:      SETTLEMENT (CUST_NM      VARCHAR(30))

同じ顧客名なのに、名前が3つ、長さも3つあります。最初は何の問題もありません。問題は、テーブルを結合するとき、統合照会を作るとき、そして3年後にデータを移行するときに噴き出します。

だからSIプロジェクトでは、開発を始める前にデータ標準を確定します。公共事業なら、「公共機関のデータベース標準化指針」に従って、標準単語・標準ドメイン・標準用語・標準コードの定義書を成果物として提出します。

標準の4段階

1. 표준단어사전   의미의 최소 단위와 그 약어
                  고객→CUST, 주문→ORD, 상품→PROD, 명칭→NM, 일자→DT,
                  금액→AMT, 수량→QTY, 번호→NO, 여부→YN, 코드→CD

2. 표준도메인     같은 성격의 값이 갖는 타입·길이 규칙
                  금액 → NUMBER(15,2)   일자 → CHAR(8)
                  여부 → CHAR(1) Y/N    코드 → VARCHAR(10)
                  명칭 → VARCHAR(100)   번호(내부키) → NUMBER(18)

3. 표준용어       단어를 조합한 논리명과 물리명
                  고객명 → CUST_NM (도메인: 명칭)
                  주문금액 → ORD_AMT (도메인: 금액)
                  주문일자 → ORD_DT (도메인: 일자)

4. 컬럼 정의      실제 DDL
                  ORD_AMT NUMBER(15,2) NOT NULL DEFAULT 0

このコードブロックの韓国語は、標準単語辞書(意味の最小単位とその略語。顧客→CUST、注文→ORD、商品→PROD、名称→NM、日付→DT、金額→AMT、数量→QTY、番号→NO、フラグ→YN、コード→CD)、標準ドメイン(同じ性質の値が持つ型・長さのルール)、標準用語(単語を組み合わせた論理名と物理名)、カラム定義(実際のDDL)の4段階についての説明です。

この順序を守れば、誰が作っても同じ名前と同じ型が出てきます。そして新しいカラムが必要なとき、「これはどのドメインか」だけを決めれば、残りは自動で決まります。

慣行についての率直な話

韓国のSIには、気に入らないかもしれない慣行があります。

前の2つはレガシー互換のためです。新しいシステムだけ違う方式にすると、連携・移行の箇所ごとに変換コードが必要になり、1か所でも漏れると、黙って誤ったデータが溜まります。そのコストが、型を改善する利点より大きくなることがあります。

標準は「最善」ではなく「合意」です。この文を理解すると、「なぜこんな古いやり方を使うのですか」という質問ではなく、「この標準をいつ、どのように変えられるか」を問うようになります。

ただし、論理削除には注意が必要です。DEL_YN='N'の条件を漏らしたクエリ1つが、削除されたデータを画面に表示してしまいます。そのため、照会は常にビューを経由するよう設計するか、最低でもコードレビューのチェックリストに入れます。

制約条件は文書ではなくコード

テーブル定義書に「必須項目」と書いてあるのに、DDLにNOT NULLがなければ、その文書は守られません。制約はDBに設定して初めて強制されます。

制約 何を防ぐか SIでの現実
PRIMARY KEY 重複行 必ず設定します
NOT NULL 必須値の欠落 必ず設定します
CHECK 値の範囲・コード値の違反 よく省略されます。設定すべきです
UNIQUE 業務キーの重複 よく省略されます。重複データ事故の元凶です
FOREIGN KEY 参照整合性 議論が分かれます
DEFAULT 想定外のNULL 設定しておくとコードが単純になります

FKが議論になる理由があります。大量バッチでFKチェックが性能を食い、移行時にロード順を強制し、論理削除と衝突します。そのため「FKは開発環境にだけ設定し、本番環境では外す」という組織もあります。

どちらにするにせよ、明示的に決めて文書化してください。最悪なのは、「あるテーブルにはあり、あるテーブルにはない」状態です。そうなると、整合性をアプリケーションが保証しているのかDBが保証しているのか、誰にもわかりません。

インデックスは設計の成果物

インデックスを「遅ければあとで追加するもの」として扱うと、サービスイン後に苦労します。設計段階で照会パターンを整理し、インデックスも一緒に設計します。

화면 SCR-021 주문조회: WHERE CUST_ID = ? AND ORD_DT BETWEEN ? AND ?
  → IX_ORDERS_01 (CUST_ID, ORD_DT)

배치 BAT-005 일마감:  WHERE ORD_DT = ? AND ORD_STS_CD = '완료'
  → IX_ORDERS_02 (ORD_DT, ORD_STS_CD)

複合インデックスのカラム順序が核心です。ルールは次のとおりです。

  1. 等価条件(=)で使うカラムを前に
  2. 範囲条件(BETWEEN、>、<)で使うカラムを後ろに
  3. 選択度の高い(値の種類が多い)カラムを前のほうに

(CUST_ID, ORD_DT)と(ORD_DT, CUST_ID)は完全に別のインデックスです。WHERE CUST_ID = ? AND ORD_DT BETWEEN ? AND ?には前者が適しています。後者は日付範囲全体を走査し、その中から顧客を絞り込まなければなりません。

そしてインデックスはタダではありません。INSERT/UPDATE/DELETEのたびにインデックスも更新されるため、インデックスが10個あるテーブルに大量にロードすると非常に遅くなります。データ移行のときにインデックスを削除してロードし、そのあと作り直す理由がこれです。

コードテーブル: ハードコーディングとの戦い

注文ステータスを'01'、'02'、'03'として保存するとします。この値の意味はどこにあるでしょうか。

SIでは、ほとんどの場合、後者です。そして多くは次のような構造です。

CREATE TABLE COMMON_CODE (
  GRP_CD  VARCHAR(20) NOT NULL,   -- 'ORD_STS'
  CD      VARCHAR(20) NOT NULL,   -- '01'
  CD_NM   VARCHAR(100) NOT NULL,  -- '접수'
  SORT_NO INTEGER NOT NULL,
  USE_YN  CHAR(1) NOT NULL DEFAULT 'Y',
  PRIMARY KEY (GRP_CD, CD)
);

注意点が1つあります。共通コードにあるからといって、何でも入ってきてはいけません。ステータスカラムにCHECKを設定するか、最低でもコード値の検証をどこで行うかを決める必要があります。「共通コードテーブルがあるから大丈夫」という言葉は、誰も検証していないという意味であることが多いです。

テーブル定義書はDBから生成します

設計の成果物としてテーブル定義書を提出しますが、開発が終わるころには、文書と実際のスキーマがずれています。いつもそうです。

そこで実務のコツです。最終的なテーブル定義書は、実際のDBメタデータから生成します。カラム一覧・型・NULL可否・デフォルト値・制約は、クエリで取り出せます。人が埋める必要があるのは説明(comment)だけです。

そして、その説明をDBのCOMMENT機能に入れておけば、文書とスキーマがいつまでも一緒に進みます。これができないDBMSを使っているなら、最低でも生成スクリプトを構成管理に置き、そこから文書を作ります。文書を手で維持した瞬間、その文書はやがて嘘になります。

現場での姿

標準を決めておきながら守られないことのほうが、よくある失敗です。定義書はあるのに、テーブルには標準にない名前が混ざっていて、誰もそれを検査しません。

そのため標準は、文書ではなく検査できる形で置く必要があります。テーブル定義書を手で書かず、pragma_table_infoやシステムカタログから生成するのも同じ理由です。手で書いた定義書は必ず実際のスキーマとずれ、ずれた定義書はないより悪いものです。読む人がそれを信じるからです。

制約条件も同じです。「数量は1以上でなければなりません」が文書にしかなければ、いつか0が入ってきます。CHECKで設定しておけば、その文章はコードになり、守られない方法がなくなります。