Ping-tの問題をやっていて、問題ID:26995のところで引っかかりました。
※Ping-tを利用するには会員登録が必要です。
「ALTER TABLE文のSET UNUSED句についての正しい記述を選べ」という問題なのですが、そこで「UNUSEDにした列のディスク領域は解放される」と答えて不正解でした。
ということで、何故UNUSEDしてもディスク領域は解放されないのか? についての備忘録を書いていきます。
- UNUSED句の概要
- ディスク領域が解放されない理由
- ディスク領域を解放するためには
(DROP UNUSED COLUMNS)
そもそもSET UNUSED句とは
SET UNUSED句は、テーブル内の指定した列を「論理的に削除」して、アプリケーションや検索(SELECT * など)からアクセスできない状態にする機能です。
削除というか、非表示のほうがイメージしやすいですね。まあ、一度SET UNUSED句を使うと再表示はできないというか、そのまま削除するしかなくなるので、「絶対削除すると決まっている列を一時的に非表示にする」処理です。
私は最初「いちいち非表示にしなくても、普通にDROP COLUMNすればいいじゃん!」と思ったものですが、DROP COLUMNでは問題が出てしまう場合があります。
というのも、DROP COLUMNは対象列の全データを削除するんですが、大量のデータが存在する大きなテーブルだった場合は、削除しきるまでに凄い負荷がかかってしまいます。
削除完了までロックがかかって追加処理も更新処理もできなくなるし、そんなんじゃサービスが止まって大損害になってしまう! というわけです。
一方、SET UNUSED句なら重いデータ削除処理を行わないため、瞬時に完了してサービスに負荷をかけません。
だからSET UNUSED句は、「とりあえず列を使えない状態にしておき、物理的な削除処理は後回しにする」という場合に使われます。パフォーマンス低下の防止用です。
削除は一旦保留して隠しておき、サービス利用者の少ない夜中などにメンテナンス時間を確保して、その時に重い削除処理をする感じです。
ディスク領域が解放されない理由
ここが今回私がPing-tで引っかかったポイントです!
「非表示にするということは、アクセスするデータが減るのだから、検索などのパフォーマンスも上がるのでは? ということは、ディスク領域は解放されるのでは?」
みたいな考えで選択して不合格です。
実際には、ただ隠しただけなので検索スピードなどは変わりません。
あくまでも隠されただけで物理的なデータ(各列の値)はディスク上のブロック内にそのまま残っているため、ディスクI/O(読み込みの負荷)自体は減りません。
それにSELECTってだいたい列名ごとに指定するので、列ごと隠されたらそれにアクセスできなくなるだけで、その他の列検索には何の影響もありませんよね。そりゃそうだ。
SELECT * で全データ抽出しようとした場合も、「見た目上、その列を無視して返す」という内部処理が行われるだけで、データを物理的にスキップして高速に読み込んでいるわけではありません。
ディスク領域を解放するためには
これまでのことを踏まえて、ディスク領域を解放するにはどうすればいいのかというと答えは簡単。物理的に削除してしまえばいいだけです。
UNUSED句を指定された列(カラム)を削除するには、以下のコマンドを使います。
ALTER TABLE テーブル名 DROP UNUSED COLUMNS;
このコマンドを実行することで、過去にSET UNUSEDに指定されたすべての列データがまとめて物理的に削除され、ディスク領域が解放されます。
業務時間中などのアクセスが多い時間帯にSET UNUSEDで素早く列を非表示にしておき、夜間や休日などシステムが空いているタイミングでDROP UNUSED COLUMNSを実行して領域を整理する、という運用の仕方をします。
ちなみに、「このUNUSED列だけを選んで個別に削除する」みたいな列指定はできません。全部まとめて「これから削除するもの」として扱われるので、ピンポイントで削除する構文自体が用意されていません。
まとめ
- SET UNUSEDは列を論理削除(隠蔽)するだけなので、ディスク領域は解放されない
- ディスク領域を物理的に解放するにはDROP UNUSED COLUMNSを実行する
「UNUSED=非表示にするだけ(領域は残る)」としっかり覚えて、試験本番に備えましょう!

コメント