データベースのサポート状況
| revision-up-to: | 7127 (0.97pre SVN) |
|---|
Django は可能な限り全てのデータベースバックエンドをサポートしようとしていま すが,残念ながら全てのサーバが全く同じ仕様というわけではないので,どの機能 をサポートすべきか,どういった仕様を仮定するかといった設計上の判断を下して います.
このドキュメントでは,このドキュメントでは, Django を使う上で関係のあるデー タベース機能について説明します.ただし,このドキュメントは特定のデータベー スサーバ向けのドキュメントとして書かれたものではなく,リファレンスマニュア ルでもありません.
MySQL に関する注意
Django はデータベースがトランザクションや参照の一貫性 (referential integrity), Unicode (UTF-8 エンコーディング) をサポートしていることを想定 して書かれています.好運なことに, MySQL バージョン 3.23 以降でこれらの機 能全てをサポートしています.従って, 3.23 や 4.0 をバックエンドとして使うの は可能なのですが, 4.1 や 5.0 を使った方がトラブルに巻き込まれにくいでしょ う.
MySQL 4.1
MySQL 4.1 では,文字セットのサポートを大幅に改良しています. 4.1 では, データベース全体から,テーブル毎,カラム毎にいたるまで個別にデフォルトの文 字セットを指定できます.以前のバージョンでは,サーバ全体に対する文字セット の設定しかできませんでした.また, 4.1 になってはじめてオンザフライで文字セッ トを変更できるようになりました. 4.1 にはビューのサポートもありますが, Django はまだこの機能をサポートしていません.
MySQL 5.0
MySQL 5.0 では,全てのデータベーススキーマに関する詳細なデータの入った information_schema というデータベースが追加されました. information_schema が存在すると, Django はこのデータベースに対して inspectdb 機能を適用します. 5.0 ではまた,ストアドプロシジャのサポート も追加されましたが, Django はまだこの機能をサポートしていません.
ストレージエンジン
MySQL は複数の ストレージエンジン (以前はテーブルタイプ: table type と呼ばれていたもの) を選択できます. デフォルトのストレージエンジンはサーバ設定で変更できます.
デフォルトのストレージエンジンは MyISAM です. MyISAM の短所は,現状ではト ランザクションや外部キーをサポートしていないという点です.一方, MyISAM は, 現状で,全文インデクスの生成や全文検索をサポートしている唯一のストレージエ ンジンです.
InnoDB エンジンは完全なトランザクション機能と外部キー参照をサポートしてい ます.
BDB エンジンは InnoDB と同様,完全なトランザクション機能を外部キー参照をサ ポートしていますが,やや時代送れになりつつあるようです.
SolidDB や Falcon といった その他のストレージエンジン まだまだ圏外の話です.現状では,おそらく InnoDB が最良の選択でしょう.
MySQLdb
MySQLdb は Python から MySQL にアクセスするためのインタフェースです. Django から利用できる MySQL の全ての機能を使うには, バージョン 1.2.1p2 以 降が必要です.それ以前のバージョンは mysql バックエンドでは動作しません.
古いバージョンの MySQL と mysql_old バックエンドを使うつもりなら, おそらく 1.2.0 で動作するでしょう.
Note
MySQLdb を Django から使おうとして ImportError: cannot import name ImmutableSet が出る場合は、おそらく MySQLdb に古い sets.py ファイルが入っていて、 Python 2.4 の同名の組 み込みモジュールと衝突しています。この問題を回避するには、 1.2.1p2 以降 の MySQLdb をインストールしてください。上書きインストールした場合には、 MySQLdb のインストールディレクトリを調べ、以前のバージョンの sets.py が入っていれば除去してください。
データベースを作成する
コマンドラインツールを使って,以下の SQL を発行すれば データベースを作成 できます:
CREATE DATABASE <dbname> CHARACTER SET utf8;
これで,全てのテーブルとカラムがデフォルトで UTF-8 を使うようになります.
データベースに接続する
設定に関するドキュメント も参照してください.
接続に関する設定は,以下の順に適用されます:
- DATABASE_OPTIONS
- DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST, DATABASE_PORT
- MySQL のオプション設定ファイル
別の言い方をするなら, DATABASE_OPTIONS 内にデータベースの名前を設定す ると,その内容は DATABASE_NAME よりも優先順位が高くなり,さらに DATABASE_NAME は MySQL のオプション設定ファイル の内容をオーバライドするということです.
MySQL のオプション設定ファイルを使う例を以下に示します:
# settings.py
DATABASE_ENGINE = "mysql"
DATABASE_OPTIONS = {
'read_default_file': '/path/to/my.cnf',
}
# my.cnf
[client]
database = DATABASE_NAME
user = DATABASE_USER
password = DATABASE_PASSWORD
default-character-set = utf8
この他にも,MySQLdb の接続オプションには, ssl, use_unicode, init_command, sql_mode といった便利なものがあります.詳しくは MySQLdb のドキュメント を参照してください.
テーブルを作成する
Django はスキーマを作成する際にストレージエンジンを指定しません.そのため, テーブルは常にサーバに設定されたデフォルトのストレージエンジンで作成されま す.作成されるテーブルを特定のタイプにしたければ,データベースサーバのデフォ ルトストレージエンジンを Django で使いたいストレージエンジンに合わせるのが 一番簡単です.
ホスティングサービスを使っていて,サーバのデフォルトのストレージエンジンを 変更できない場合,二つの選択肢があります.
テーブルが作成された後に,以下のようなクエリを発行して,ストレージ エンジンを (InnoDB) などに変更します:
ALTER TABLE <tablename> ENGINE=INNODB;テーブルが沢山ある場合には,これは相当骨がおれることでしょう.
あるいは,テーブルを作成する前に, MySQLdb の init_command オプショ ンを使います:
DATABASE_OPTIONS = { ... "init_command": "SET storage_engine=INNODB", ... }このように設定しておくと,接続時にデフォルトのストレージエンジンが変更 されます.ただし,テーブルが全て作成され,運用環境で動き始めたら,この オプションを外しておかねばなりません.
syncdb 時にストレージエンジンを変更するもう一つの方法は, Wiki の AlterModelOnSyncDB に記載されています.
Oracle に関する注意
Django はバージョン 9i 以降の Oracle データベースサーバ をサポートしてい ます。 Django の regex および iregex クエリオペレータを使うには、 バージョン 10g 以降の Oracle を使う必要があります。 バージョン 4.3.1 以降の cx_Oracle ドライバが必要です。
Oracle で python manage.py syncdb コマンドを動かすには、データベースユー ザに以下のコマンドを実行できる権限が必要です:
- CREATE TABLE
- CREATE SEQUENCE
- CREATE PROCEDURE
- CREATE TRIGGER
Django のテストスイートを実行させるには、 さらに 以下の権限が必要です:
- CREATE DATABASE
- DROP DATABASE
- CREATE TABLESPACE
- DROP TABLESPACE
データベースへの接続
Oracle を使う場合、 Django の settings.py は以下のように設定します:
DATABASE_ENGINE = 'oracle' DATABASE_NAME = 'xe' DATABASE_USER = 'a_user' DATABASE_PASSWORD = 'a_password' DATABASE_HOST = '' DATABASE_PORT = ''
tnsnames.ora ファイルや、 SID として扱われる名前 (上の例では "xe") を使わない場合は、以下のように DATABASE_HOST および DATABASE_PORT を設定してください:
DATABASE_ENGINE = 'oracle' DATABASE_NAME = 'xe' DATABASE_USER = 'a_user' DATABASE_PASSWORD = 'a_password' DATABASE_HOST = 'dbprod01ned.mycompany.com' DATABASE_PORT = '1540'
DATABASE_HOST と DATABASE_PORT は、両方とも指定するか、両方とも空に するかどちらかにしてください。
テーブルスペース
Oracle ベースのシステムでパフォーマンス向上に使われているパラダイムとして、 「 テーブルスペース (tablespace)」によるディスクレイアウトの構築がありま す。 db_tablespace オプションを Meta と Field クラスに追加する と、 Oracle バックエンドはテーブルスペースを利用します (バックエンドがテー ブルスペースをサポートしなければ、 Django はこのオプションを無視します)。
モデルのテーブルにテーブルスペースを指定するには、モデルの内部クラス Meta に db_tablespace オプションを指定します。モデル全体とは別のテー ブルスペースをフィールドのカラムインデクスに指定したければ、フィールドのコ ンストラクタに db_tablespace を指定します。カラムごとにインデクスを生成 しない場合には、 db_tablespace オプションは無視されます。
class TablespaceExample(models.Model):
name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
data = models.CharField(max_length=255, db_index=True)
edges = models.ManyToManyField(to="self", db_tablespace="indexes")
class Meta:
db_tablespace = "tables"
上の例では、 TablespaceExample モデルの生成するテーブル (モデルテーブルと多対多のリレーションのテーブル) は、 tables という名前 のテーブルスペースに保存されます。 name フィールドと、多対多リレーショ ンテーブルのインデクスは indexes テーブルスペースに保存されます。 data フィールドもインデクスを生成しますが、このインデクスのテーブルスペー スは指定されていないので、デフォルトの挙動としてテーブルスペース tables に保存されます。
開発版の Django で新たに登場した機能: db_tablespace オプションのデフォルト値を指定するには、 DEFAULT_TABLESPACE および DEFAULT_INDEX_TABLESPACE 設定を使います。 これらの設定は、組み込みの Django アプリケーションや、ソースコードをいじれ ないアプリケーションに対してテーブルスペースを指定する場合に便利です。
Django 自体にはテーブルスペースを作成する機能はありません。 テーブルスペースの作成や管理の方法は、 Oracle のドキュメント を参照して ください。
名前に関する制約
Oracle は名前の長さを 30 文字以下に制限しています。この制限に合わせるために、 バックエンドは識別子名を切り詰めて、最後の 4 文字を MD5 のハッシュ値で置き 換えます。
NULL 値よび空文字列
Django は通常、 NULL ではなく空文字列を使うようにしていますが、 Oracle はこ れらを別々のものとして扱います。この問題を回避するには、 Oracle バックエン ドは空文字列を値として受け入れるフィールドに null=Ture オプションを 強制的に付加します。データベースから値を取り出すとき、フィールドの値が NULL であれば、そのフィールドの値は実際には空文字列であるとみなし、値も暗黙のう ちに空文字列に変換されます。
TextField への制限
Oracle バックエンドは TextField を NCLOB カラム形式で保存します。 Oracle は、一般に LOB カラムに以下の制約を課しています:
- LOB カラムは主キーにできません。
- LOB カラムはインデクス化に使えません。
- LOB カラムは SELECT DISTINCT できません。従って、Oralce バックエン ドを使っていて、 TextField カラムを含むモデルに対して QuerySet.distinct を行うとエラーを引き起こします。このエラーを避け るには、 distinct() クエリの対象モデルから TextField を除去し、 TextField を持つ他のモデルを定義しておいてリレーションを張ってくだ さい。