doodle-on-web

自分で調べたことや、仕事の中で質問されたことなどをまとめています。

`dbo`を省略したら別テーブルを参照していた——SQL Serverスキーマの正しい理解

スポンサーリンク

SQL Serverを触っていると、テーブル名の前に必ずと言っていいほど付いてくる「dbo」という文字。SELECT * FROM dbo.Users のように書かれているのを見て、「これは一体何なのだろう?」と疑問に思った方も多いのではないでしょうか。

この記事では、SQL Serverにおける「dbo」の正体と、スキーマの基礎、そして省略したときに何が起こるのかを実践的に解説します。実はこの仕組みを知らないと、まったく同じSQLが実行する人によって違う結果を返すという、地味だが厄介な事故に遭遇することがあります。まずはその落とし穴の正体から見ていきましょう。

そもそもスキーマとは何か

「dbo」を理解するには、まず「スキーマ(Schema)」という概念を押さえる必要があります。

スキーマとは、データベース内でテーブルやビュー、ストアドプロシージャなどのオブジェクトをまとめる「入れ物」「名前空間」のようなものです。ファイルをフォルダで整理するのと同じイメージで、データベース内のオブジェクトをグループ分けする仕組みだと考えるとわかりやすいでしょう。

SQL Serverのオブジェクトは、正式には次の4階層で識別されます。

サーバー名.データベース名.スキーマ名.オブジェクト名

例えば MyServer.SalesDB.dbo.Users のような形です。普段はサーバー名やデータベース名を省略して dbo.Users と書くことが多いですが、内部的にはこの階層構造で管理されています。

「dbo」の正体

結論から言うと、dbo は「database owner(データベース所有者)」の略で、SQL Serverにデフォルトで用意されている標準スキーマです。

新しくデータベースを作成すると、この dbo スキーマが自動的に存在しています。そして、スキーマを明示的に指定せずにテーブルを作成すると、そのテーブルは通常 dbo スキーマに所属します。つまり、多くの現場で目にする dbo.テーブル名 という表記は、「デフォルトのスキーマに属するテーブル」を指しているわけです。

特別な設計をしていないデータベースでは、ほぼすべてのオブジェクトが dbo スキーマに入っているケースが非常に多いです。ただし一点、Windows認証ユーザーが自分のデフォルトスキーマを持たないまま CREATE TABLE すると、[ドメイン\ユーザー].テーブル のようなユーザー名スキーマが勝手に作られて混乱する、という古典的なハマりもあります。

スキーマ名を省略するとどうなるか

ここが本記事の核心です。結論から言えば、省略時の解決先はユーザーによって変わり得ます。

次のようにスキーマ名を省略してクエリを書いたとします。

SELECT * FROM Users;

このようなスキーマ修飾なしのテーブル/ビュー参照では、SQL Serverは以下の順序でオブジェクトを探します。

  1. 実行しているユーザーに設定されたデフォルトスキーマの中を探す
  2. 見つからなければ dbo スキーマの中を探す

つまり、ログインユーザーのデフォルトスキーマが dbo であれば Usersdbo.Users として解決されますが、デフォルトスキーマが sales に設定されている場合、まず sales.Users を探しに行きます。

この挙動が思わぬバグの原因になります。開発者Aと開発者Bでデフォルトスキーマが異なると、同じSQLを実行しても違うテーブルを参照してしまうという事故が起こり得るのです。(なお、ストアドプロシージャの EXEC などは別の解決ルールになります。)

自分のデフォルトスキーマを確認する

「もしかして自分もハマっているかも」と思ったら、次のクエリで現在のユーザーのデフォルトスキーマを確認できます。

SELECT name, default_schema_name
FROM sys.database_principals
WHERE name = USER_NAME();

スキーマ名は明示的に書くべき

こうしたトラブルを避けるため、実務ではスキーマ名を省略せず明示的に書くことが強く推奨されます。

-- 非推奨(環境によって解決先が変わる可能性がある)
SELECT * FROM Users;

-- 推奨(常に同じテーブルを参照する)
SELECT * FROM dbo.Users;

スキーマ名を明示するメリットは主に3つあります。

  • 一意性の保証:どのユーザーが実行しても同じオブジェクトを参照する
  • 実行プランキャッシュの再利用:スキーマを省略すると、実行ユーザーのデフォルトスキーマごとに別々の実行プランが生成され、キャッシュが無駄に膨張してヒット率が下がります。明示すればプランが共有され、キャッシュが効率的に使われます
  • 可読性の向上:どのスキーマのテーブルかが一目でわかる

dbo以外のスキーマを使う場面

「それなら全部 dbo でいいのでは?」と思うかもしれませんが、大規模なシステムでは意図的にスキーマを分けることがあります。

例えば、sales(営業)、hr(人事)、inventory(在庫)のように業務ドメインごとにスキーマを分割すると、オブジェクトの整理がしやすくなります。さらに、スキーマ単位で権限を付与できるため、「営業チームには sales スキーマだけアクセスを許可する」といったセキュリティ制御も容易になります。

新しいスキーマの作成は次のように行います。

CREATE SCHEMA sales;

CREATE TABLE sales.Orders (
    OrderId INT PRIMARY KEY,
    Amount  DECIMAL(10, 2)
);

まとめ

最後にポイントを整理します。

  • dbo は「database owner」の略で、SQL Serverの標準デフォルトスキーマ
  • スキーマは、オブジェクトを整理する名前空間の役割を持つ
  • スキーマ修飾なしのテーブル参照は、ユーザーのデフォルトスキーマ→dbo の順で解決される
  • 事故防止・プランキャッシュ効率・可読性のため、スキーマ名は明示的に書くのが実務のベストプラクティス
  • 大規模システムでは、業務ドメインごとにスキーマを分けると管理・権限制御がしやすくなる

普段何気なく書いている dbo. には、こうした明確な意味と動作の仕組みがあります。まずは先ほどの確認クエリで、自分のデフォルトスキーマをチェックしてみてください。次回は、ここで触れたスキーマ単位の権限設計をもう一歩踏み込んで扱う予定です。