データベースのサポート状況

revision-up-to:11321 (1.1) unfinished

Django は可能な限り全てのデータベースバックエンドをサポートしようとしていま すが、残念ながら全てのサーバが全く同じ仕様というわけではないので、どの機能 をサポートすべきか、どういった仕様を仮定するかといった設計上の判断を下して います。

このドキュメントでは、このドキュメントでは、 Django を使う上で関係のあるデー タベース機能について説明します。ただし、このドキュメントは特定のデータベー スサーバ向けのドキュメントとして書かれたものではなく、リファレンスマニュア ルでもありません。

PostgreSQL notes

PostgreSQL 8.2 to 8.2.4

The implementation of the population statistics aggregates STDDEV_POP and VAR_POP that shipped with PostgreSQL 8.2 to 8.2.4 are known to be faulty. Users of these releases of PostgreSQL are advised to upgrade to Release 8.2.5 or later. Django will raise a NotImplementedError if you attempt to use the StdDev(sample=False) or Variance(sample=False) aggregate with a database backend that falls within the affected release range.

Transaction handling

By default, Django starts a transaction when a database connection is first used and commits the result at the end of the request/response handling. The PostgreSQL backends normally operate the same as any other Django backend in this respect.

Autocommit mode

If your application is particularly read-heavy and doesn’t make many database writes, the overhead of a constantly open transaction can sometimes be noticeable. For those situations, if you’re using the postgresql_psycopg2 backend, you can configure Django to use “autocommit” behavior for the connection, meaning that each database operation will normally be in its own transaction, rather than having the transaction extend over multiple operations. In this case, you can still manually start a transaction if you’re doing something that requires consistency across multiple database operations. The autocommit behavior is enabled by setting the autocommit key in the DATABASE_OPTIONS setting:

DATABASE_OPTIONS = {
    "autocommit": True,
}

In this configuration, Django still ensures that delete() and update() queries run inside a single transaction, so that either all the affected objects are changed or none of them are.

This is database-level autocommit

This functionality is not the same as the topics-db-transactions-autocommit decorator. That decorator is a Django-level implementation that commits automatically after data changing operations. The feature enabled using the DATABASE_OPTIONS settings provides autocommit behavior at the database adapter level. It commits after every operation.

If you are using this feature and performing an operation akin to delete or updating that requires multiple operations, you are strongly recommended to wrap you operations in manual transaction handling to ensure data consistency. You should also audit your existing code for any instances of this behavior before enabling this feature. It’s faster, but it provides less automatic protection for multi-call operations.

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 [1] です。 MyISAM の短所は、現状 ではトランザクションや外部キーをサポートしていないという点です。一方、 MyISAM は、現状で、全文インデクスの生成や全文検索をサポートしている唯一のス トレージエンジンでもあります。

InnoDB エンジンは完全なトランザクション機能と外部キー参照をサポートしてい ます。

BDB エンジンは InnoDB と同様、完全なトランザクション機能を外部キー参照をサ ポートしていますが、やや時代送れになりつつあるようです。

SolidDBFalcon といった その他のストレージエンジン まだまだ圏外の話です。現状では、おそらく InnoDB が最良の選択でしょう。

[1]お使いの MySQL パッケージでデフォルトが変更されていない場合。 Windows Community Server 向けのインストーラは、デフォルトのストレージエ ンジンを InnoDB にしているという報告があります。

MySQLdb

MySQLdb は Python から MySQL にアクセスするためのインタフェースです。 Django から利用できる MySQL の全ての機能を使うには、 バージョン 1.2.1p2 以 降が必要です。

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 を使うようになります。

コレーションに関する設定

カラムのコレーション設定は、データの保存方法や、文字列の等価性の定義を制御 しています。コレーションはデータベース全体でも、テーブル単位でも、カラム単 位でも設定できます。コレーションの詳細は MySQL のドキュメントで 詳しく解説されています 。いずれの場合でも、 コレーションの設定は直接データベーステーブルに対して行ってください。 Django はモデル定義でコレーションを設定する方法を提供していません。

デフォルトの構成では、 MySQL は UTF-8 のデータベースに対して utf8_general_ci_swedish コレーションを使います。この設定では、全ての文 字列の等値比較が 大小文字を区別 せず行われます。つまり、 "Fred""freD" はデータベースレベルでは同じ値だとみなされるのです。そのため、デ フォルトのコレーションを使っていると、フィールドに unique 制約をかけた ときに、 "aa""AA" は等しいとみなされ (一意性が破れるので) 同じ カラムに入れられなくなります。

大抵のケースでは、デフォルトの設定はさして問題を起こしません。しかし、特定 のカラムやテーブルで大小文字を区別させたいなら、そのカラムやテーブルに utf8_bin コレーションを指定せねばなりません。その場合、注意すべきなのは、 MySQLdb 1.2.2 を使っていると、 Django のデータベースバックエンドが、データ ベースから取り出した文字列フィールドの値として (unicode 文字列ではなく) bytestring を返すということです。このふるまいは、 常に unicode を返す、と いう Django の通常のやりかたから大きくかけ離れています。コレーションを utf8_bin にして、 bytestring を受け取ったときの扱いは、開発者に委ねられ ています。 Django 自体はこのカラムを問題なく扱えますが、一貫性をもってデー タを処理したければ、 django.utils.encoding.smart_unicode() を何度も 呼び出すことになるでしょう。(データベースバックエンドレイヤとモデルの操作レ イヤは内部的に分離しているため、変換が必要かどうかをデータベースレイヤでは 判断できないので) Django はこの変換に関知しないのです。

MySQLdb 1.2.1p2 を使っているなら、コレーションを utf8_bin にしても、 CharField は unicode 文字列を返します。しかし、 今度は TextField が (Python 標準モジュール array の) array.array を返します。データをデータベースから読み出す ときに、変換に必要な情報が手にはいらないので、 Django 側ではどうしようもあ りません。この問題は MySQLdb 1.2.2 で解決済み なので、 itf8_bin コレーションで TextField を使いたければ、バージョンを 1.2.2 に上げて、バイト文字列として扱うよう勧め ます (それほど難しくはありません)。

MySQLdb 1.2.1p2 で utf8_bin コレーションの設定されたテーブルを使うのな ら、 django.contrib.sessions.models.Session のテーブル (通常は django_session) や、 django.contrib.admin.models.LogEntry のテーブル (通常は django_admin_log) のコレーションに utf8_collation_ci_swedish (デフォルトのコレーション) を使わねばなりませ ん。これらは標準の Django のテーブルのうち、内部的に TextField を使っているからです。

データベースに接続する

設定に関するドキュメント を参照してください。

接続に関する設定は、以下の順に適用されます:

別の言い方をするなら、 DATABASE_OPTIONS 内にデータベースの名前を 設定すると、その内容は DATABASE_NAME よりも優先順位が高くなり、 さらに DATABASE_NAMEMySQL のオプション設定ファイル の内容 をオーバライドするということです。

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 に記載されています。

フィールドタイプごとの注意

BooleanField

MySQL には直接的な BOOLEAN カラム型がないので、 Django は BooleanField の値を TINYINT カラムを使って 0 または 1 で保存します。詳しくはモデルフィールドのドキュメントを参照してくだ さい。ただし、フィールドの値を出力したり、値が TrueFalse でなけ ればならないような場合を除いて、特に問題はありません。

Character fields

Any fields that are stored with VARCHAR column types have their max_length restricted to 255 characters if you are using unique=True for the field. This affects CharField, SlugField and CommaSeparatedIntegerField.

Furthermore, if you are using a version of MySQL prior to 5.0.3, all of those column types have a maximum length restriction of 255 characters, regardless of whether unique=True is specified or not.

SQLite に関する注意

SQLite provides an excellent development alternative for applications that are predominantly read-only or require a smaller installation footprint. As with all database servers, though, there are some differences that are specific to SQLite that you should be aware of.

String matching for non-ASCII strings

SQLite doesn’t support case-insensitive matching for non-ASCII strings. Some possible workarounds for this are documented at sqlite.org, but they are not utilised by the default SQLite backend in Django. Therefore, if you are using the iexact lookup type in your queryset filters, be aware that it will not work as expected for non-ASCII strings.

Version 3.5.9

The Ubuntu “Intrepid Ibex” (8.10) SQLite 3.5.9-3 package contains a bug that causes problems with the evaluation of query expressions. If you are using Ubuntu “Intrepid Ibex”, you will need to update the package to version 3.5.9-3ubuntu1 or newer (recommended) or find an alternate source for SQLite packages, or install SQLite from source.

At one time, Debian Lenny shipped with the same malfunctioning SQLite 3.5.9-3 package. However the Debian project has subsequently issued updated versions of the SQLite package that correct these bugs. If you find you are getting unexpected results under Debian, ensure you have updated your SQLite package to 3.5.9-5 or later.

The problem does not appear to exist with other versions of SQLite packaged with other operating systems.

Version 3.6.2

SQLite version 3.6.2 (released August 30, 2008) introduced a bug into SELECT DISTINCT handling that is triggered by, amongst other things, Django’s DateQuerySet (returned by the dates() method on a queryset).

You should avoid using this version of SQLite with Django. Either upgrade to 3.6.3 (released September 22, 2008) or later, or downgrade to an earlier version of SQLite.

Using newer versions of the SQLite DB-API 2.0 driver

For versions of Python 2.5 or newer that include sqlite3 in the standard library Django will now use a pysqlite2 interface in preference to sqlite3 if it finds one is available.

This provides the ability to upgrade both the DB-API 2.0 interface or SQLite 3 itself to versions newer than the ones included with your particular Python binary distribution, if needed.

“Database is locked” errors

SQLite is meant to be a lightweight database, and thus can’t support a high level of concurrency. OperationalError: database is locked errors indicate that your application is experiencing more concurrency than sqlite can handle in default configuration. This error means that one thread or process has an exclusive lock on the database connection and another thread timed out waiting for the lock the be released.

Python’s SQLite wrapper has a default timeout value that determines how long the second thread is allowed to wait on the lock before it times out and raises the OperationalError: database is locked error.

If you’re getting this error, you can solve it by:

  • Switching to another database backend. At a certain point SQLite becomes too “lite” for real-world applications, and these sorts of concurrency errors indicate you’ve reached that point.

  • Rewriting your code to reduce concurrency and ensure that database transactions are short-lived.

  • Increase the default timeout value by setting the timeout database option option:

    DATABASE_OPTIONS = {
        # ...
       "timeout": 20,
        # ...
    }
    

    This will simply make SQLite wait a bit longer before throwing “database is locked” errors; it won’t really do anything to solve them.

Oracle に関する注意

Django はバージョン 9i 以降の Oracle データベースサーバ をサポートしてい ます。 Django の regex および iregex クエリオペレータを使うには、 バージョン 10g 以降の Oracle を使う必要があります。 バージョン 4.3.1 以降の cx_Oracle ドライバが必要です。

Note that due to a Unicode-corruption bug in cx_Oracle 5.0, that version of the driver should not be used with Django; cx_Oracle 5.0.1 resolved this issue, so if you’d like to use a more recent cx_Oracle, use version 5.0.1.

Oracle で python manage.py syncdb コマンドを動かすには、データベースユー ザに以下のコマンドを実行できる権限が必要です:

  • CREATE TABLE
  • CREATE SEQUENCE
  • CREATE PROCEDURE
  • CREATE TRIGGER

Django のテストスイートを実行させるには、 さらに 以下の権限が必要です:

  • CREATE USER
  • DROP USER
  • CREATE TABLESPACE
  • DROP TABLESPACE
  • CONNECT WITH ADMIN OPTION
  • RESOURCE WITH ADMIN OPTION

データベースへの接続

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_HOSTDATABASE_PORT は、両方とも指定するか、 両方とも空にするかどちらかにしてください。

テーブルスペース

Oracle ベースのシステムでパフォーマンス向上に使われているパラダイムとして、 「 テーブルスペース (tablespace)」によるディスクレイアウトの構築がありま す。 db_tablespace オプションを MetaField クラスに追加する と、 Oracle バックエンドはテーブルスペースを利用します (バックエンドがテー ブルスペースをサポートしなければ、 Django はこのオプションを無視します)。

モデルのテーブルにテーブルスペースを指定するには、モデルの内部クラス Metadb_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 に保存されます。

db_tablespace オプションのデフォルト値を指定するには、 DEFAULT_TABLESPACE および DEFAULT_INDEX_TABLESPACE 設 定を使います。これらの設定は、組み込みの Django アプリケーションや、ソース コードをいじれないアプリケーションに対してテーブルスペースを指定する場合に 便利です。

Django 自体にはテーブルスペースを作成する機能はありません。 テーブルスペースの作成や管理の方法は、 Oracle のドキュメント を参照して ください。

名前に関する制約

Oracle は名前の長さを 30 文字以下に制限しています。この制限に合わせるために、 バックエンドは識別子名を切り詰めて、最後の 4 文字を MD5 のハッシュ値で置き 換えます。

NULL 値よび空文字列

Django は通常、 NULL ではなく空文字列を使うようにしていますが、 Oracle はこ れらを別々のものとして扱います。この問題を回避するには、 Oracle バックエン ドは空文字列を値として受け入れるフィールドに null=Ture オプションを 強制的に付加します。データベースから値を取り出すとき、フィールドの値が NULL であれば、そのフィールドの値は実際には空文字列であるとみなし、値も暗黙のう ちに空文字列に変換されます。

TextField への制限

Oracle バックエンドは TextFieldNCLOB カラム形式で保存します。 Oracle は、一般に LOB カラムに以下の制約を課しています:

  • LOB カラムは主キーにできません。
  • LOB カラムはインデクス化に使えません。
  • LOB カラムは SELECT DISTINCT できません。従って、Oralce バックエン ドを使っていて、 TextField カラムを含むモデルに対して QuerySet.distinct を行うとエラーを引き起こします。このエラーを避け るには、 distinct() クエリの対象モデルから TextField を除去し、 TextField を持つ他のモデルを定義しておいてリレーションを張ってくだ さい。

Using a 3rd-party database backend

In addition to the officially supported databases, there are backends provided by 3rd parties that allow you to use other databases with Django:

The Django versions and ORM features supported by these unofficial backends vary considerably. Queries regarding the specific capabilities of these unofficial backends, along with any support queries, should be directed to the support channels provided by each 3rd party project.