🚧

Db2の「SQL0668N 操作は許可されません」を理由コードで即断する ― LOAD後・ALTER後に表が読めない/書けないとき

に公開

一括ロードのあと、あるいは ALTER TABLE を流したあと、その表に触ろうとしたら急にこれが返る——SQL0668N「操作は理由コード〜のため許可されません」。SELECTすら弾かれることがあり、「表が壊れた?」と焦りがちですが、ほとんどは表が一時的に制限状態に入っているだけで、理由コードを見れば抜け方は機械的に決まります。

厄介なのは、SQL0668N理由コードごとに対処がまったく違う点です。「ログ保留だから REORG」と決め打ちすると、実は LOAD の失敗(理由コード3)で、REORG では抜けられない、といったことが起きます。

この記事では、SQL0668N が出たときに理由コードから状態を特定し、正しい抜け方に一直線で進む手順を解説します。

まず結論:SQL0668N は「表が制限状態」。理由コードで状態が確定する

SQL0668N のSQLSTATEは 57007。メッセージには必ず理由コードが付いていて、これで表がどの制限状態にあるかが一意に決まります。

SQL0668N  Operation not allowed for reason code "3" on table "MYSCHEMA.SALES".

理由コードは1〜13までありますが、現場で遭遇するのはほぼ次の5つです(全リストは db2 "? SQL0668N" で確認できます)。

理由コード 状態 どういうとき起きるか 抜け方
3 Load Pending LOAD が失敗して中断した LOAD ... RESTART または TERMINATE
1 Set Integrity Pending(No Access) LOAD 後や制約付き ALTER 後、整合性未検証 SET INTEGRITY ... IMMEDIATE CHECKED
4 Read Access オンラインLOAD中/後、制約検証前(読取のみ可 SET INTEGRITY ... IMMEDIATE CHECKED
7 Reorg Pending REORG推奨の ALTER TABLE を重ねた REORG TABLE
8 Alter Pending 同一UOW内でREORG推奨のALTERをした COMMIT する

まず理由コードを読み、それでも状態を裏取りしたければ、次のクエリでカタログ上の状態を確認します。

ステップ1:表がどの制限状態にあるかを確認する

理由コードだけで判断できるのが理想ですが、複数の状態が絡むときや、そもそもどの表が制限中かを洗い出したいときは SYSCAT.TABLES を見ます。見るべきは3列です。

-- 表の制限状態を確認する
SELECT
    VARCHAR(TABNAME,20)      AS TAB,
    STATUS,                  -- N=通常 / C=check pending / X=inoperative
    ACCESS_MODE,             -- F=全アクセス可 / N=不可 / R=読取のみ / D=データ移動不可
    SUBSTR(CONST_CHECKED,1,8) AS CONST_CHECKED  -- 各制約の検証状態(Y/N/...)
FROM SYSCAT.TABLES
WHERE TABSCHEMA = 'MYSCHEMA'
  AND TYPE = 'T';

通常の(制限のない)表はこう見えます。検証環境のSAMPLEの表を例にすると次の通りです。

TAB              STATUS  ACCESS_MODE  CONST_CHECKED
---------------- ------  -----------  -------------
EMPLOYEE         N       F            YYYYYY
DEPARTMENT       N       F            YYYYYY
PROJECT          N       F            YYYYYY

STATUS='N'(通常)・ACCESS_MODE='F'(全アクセス可)・CONST_CHECKED が全て Y なら、その表は制限されていません。SQL0668N の対象表は、ここが次のように変わります。

  • STATUS='C'(check pending)+ACCESS_MODE='N' … 理由コード1(Set Integrity Pending, No Access)。読み書きとも不可。
  • STATUS='C'ACCESS_MODE='R' … 理由コード4(Read Access)。読取のみ可。
  • CONST_CHECKEDN が混じる … その制約がまだ検証されていない。SET INTEGRITY で検証すべき対象。

STATUS が check pending 以外(例えばinoperative X)なら別系統の問題です。LOAD 絡みかどうかは LOAD QUERY が最も確実です。

# 表がロード保留/ロード中かを確認する
db2 "LOAD QUERY TABLE MYSCHEMA.SALES"

これで Load pendingLoad in progressNormal のいずれかが分かります。理由コード3か5かの決め手になります。

なお、同じ「触れない」でも、その表だけでなく同じ表スペース上の表がすべて弾かれるなら、原因は表ではなく表スペース側の状態で、返るエラーも SQL0290N になります。この場合は SET INTEGRITYREORG では抜けられないので、MON_GET_TABLESPACETBSP_STATE を先に確認してください。

https://zenn.dev/firese/articles/db2-sql0290n-tablespace-access

ステップ2:理由コード別の抜け方

理由コード3(Load Pending)── LOADの失敗が原因

LOAD が途中で失敗すると、表は Load Pending に入り、LOAD を「完了させる」か「無かったことにする」まで一切触れなくなります。REORG でも SET INTEGRITY でも抜けられません。抜け方は2つ。

# 途中まで入ったデータを活かして続きから完了させる
db2 "LOAD FROM /data/sales.del OF DEL RESTART INTO MYSCHEMA.SALES"

# 失敗したLOADを破棄して、LOAD直前の状態に戻す
db2 "LOAD FROM /dev/null OF DEL TERMINATE INTO MYSCHEMA.SALES"

原因(入力ファイルの不正、領域不足など)を直せるなら RESTART、まっさらに戻したいなら TERMINATE です。

理由コード1・4(Set Integrity Pending)── 制約の検証待ち

LOAD(オンラインでない通常ロード)の後や、外部キー・チェック制約を伴う ALTER TABLE ... ADD CONSTRAINT の後、Db2は追加された部分の制約をまだ検証していない状態=Set Integrity Pending に表を置きます。理由コード1は読み書き不可、理由コード4は読取のみ可の違いです。抜け方は共通で SET INTEGRITY です。

# 制約を検証して通常状態に戻す
db2 "SET INTEGRITY FOR MYSCHEMA.SALES IMMEDIATE CHECKED"

このとき、制約に違反する行があると SET INTEGRITY 自体が失敗します。違反行を例外表に逃がしながら検証を通すこともできます。

db2 "SET INTEGRITY FOR MYSCHEMA.SALES IMMEDIATE CHECKED
     FOR EXCEPTION IN MYSCHEMA.SALES USE MYSCHEMA.SALES_EXCEPTION"

理由コード7(Reorg Pending)── ALTERの積み重ねが原因

ALTER TABLE で列のサイズ変更などREORG推奨の変更を(1つのUOW内で3回など)重ねると、表が Reorg Pending に入り、REORG するまで使えなくなります。

db2 "REORG TABLE MYSCHEMA.SALES"

なお Reorg Pending の表はインプレースREORG(INPLACE)では抜けられません。通常の(オフライン)REORG TABLE を使います。

理由コード8(Alter Pending)── コミットで抜ける

同一トランザクション内でREORG推奨の ALTER をした直後にその表へアクセスすると理由コード8になります。これは単にその作業単位をコミットすれば解消します。

db2 "COMMIT"

SQL0668N が出たときのチェックリスト

  1. メッセージの理由コードを読む(db2 "? SQL0668N" で全リスト)
  2. 迷ったら SYSCAT.TABLESSTATUSACCESS_MODECONST_CHECKED で状態を裏取り
  3. LOAD 絡みが疑わしければ LOAD QUERY TABLE ... で Load pending / in progress を確認
  4. 理由3(Load Pending)… LOAD ... RESTARTTERMINATE で後始末(REORGでは抜けない)
  5. 理由1・4(Set Integrity Pending)… SET INTEGRITY ... IMMEDIATE CHECKED。違反行は例外表へ
  6. 理由7(Reorg Pending)… オフライン REORG TABLEINPLACE不可)
  7. 理由8(Alter Pending)… COMMIT
  8. 恒久対策は「LOAD失敗時の後始末を手順化」+「制約付きALTER/LOAD後のSET INTEGRITYをジョブに組み込む

📕 もっと深く:Db2運用を12章で体系化した本を書きました

この記事で扱った SQL0668N の切り分けは、Db2運用のほんの一部です。

Db2はRDBMS市場でシェア数%。情報が少なく、頼れるのは膨大な公式マニュアルだけ——そんな現状を変えたくて、「なぜこの値にするのか」「この障害のとき次に何を見るのか」という、マニュアルに載っていない現場の文脈を1冊にしました。実機で検証した内容と、Db2の設計上そうなる理由をまとめました。

アーキテクチャ/構成パラメーター選定/セキュリティ/バックアップ・リカバリ/HADR/pureScale/日常点検の自動化/メモリ・ロック競合/SQLチューニング/RUNSTATS・REORGを意図して制御する/MON_GET監視/現場の難題・解決集まで、全12章+運用シェルスクリプト集です。

https://zenn.dev/firese/books/db2-practical-bible

Db2の運用で踏んだ地雷や、扱ってほしいテーマがあれば、ぜひコメントで教えてください。次の記事のネタにさせてもらいます。

Discussion