3

これまで、私たちのアプリケーションは、SQLObject を ORM として持つ 1 つの SQLite データベースを使用していました。明らかに、ある時点で、SQLite の同時実行性の問題に直面しなければならないことがわかっていたので、そうしました。

現在のデータベースを複数のデータベースに分割することになりました。つまり、各テーブル スキーマは同じままでしたが、さまざまなテーブルを複数のデータベースに分散し、テーブルを密結合したままにしました。

これは、アプリケーションの新しいバージョンのクリーン インストールでは非常にうまく機能しますが、アプリケーションの以前のバージョンからこの新しいバージョンにアップグレードするには、アプリケーションが機能し始める前に特別なデータ移行が必要です。この場合、データベースの移行は、この単一のデータベースから適切な別のデータベースにテーブルを移動するだけです。

例として、これが古い構造であると考えてください。

single_db.db --- 単一のデータベース

 * A -- Table A
 * B -- Table B
 * C -- Table C
 * D -- Table D
 * E -- Table E
 * F -- Table F

新しい構造:

db1.db --- データベース 1

 - A -- Table A
 - B -- Table B
 - C -- Table C
 - D -- Table D

db2.db --- データベース 2

 - E -- Table E

db3.db --- データベース 3

 - F -- Table F

アップグレードが行われると、アプリケーションは上記の 3 つのデータベースと空のテーブルを含む新しい構造を作成します。また、すべてのテーブルと実際のデータを含む古いデータベース single_db.db も存在します。アプリケーションが動作を開始する前に、テーブルを移動するか、古いデータベースのテーブルから、対応する新しいデータベースの対応するテーブルにデータをコピーする必要があります。

このデータベース移行のコードを書く必要があります。古いデータベース接続を使用してテーブルをクエリし、新しいデータベース接続を使用して、返された行を対応するテーブルに挿入できることはわかっています。ここで注意する必要があるのは、これらのテーブルの一部には多数の行を含めることができるということです。つまり、行は 2/3 テーブルで 2 ~ 250 万まで可能です。

SQLiteの上でSQLObjectを使用していて、以前に誰かがこれを行ったことがあるので、他のSLQObjectトリックを使用できるかどうか尋ねたいですか?

ご協力いただきありがとうございます。

4

1 に答える 1

1

おそらくこれで解決したと思いますが、グーグルで調べている人にとっては、OPとほぼ同じことをしなければなりませんでした。これは、使用したコードのコア部分でした(見つけたものから変更されていますが、見つかりません再び元の作者のクレジットを表示します。申し訳ありません!)

def _iterdump(connection, table_name):
    """
    Returns an iterator to dump a database table in SQL text format.
    """

    cu = connection.cursor()

    yield('BEGIN TRANSACTION;')

    # sqlite_master table contains the SQL CREATE statements for the database.
    q = """
       SELECT name, type, sql
        FROM sqlite_master
            WHERE sql NOT NULL AND
            type == 'table' AND
            name == :table_name
        """
    schema_res = cu.execute(q, {'table_name': table_name})
    for table_name, type, sql in schema_res.fetchall():
        if table_name == 'sqlite_sequence':
            yield('DELETE FROM sqlite_sequence;')
        elif table_name == 'sqlite_stat1':
            yield('ANALYZE sqlite_master;')
        elif table_name.startswith('sqlite_'):
            continue
        else:
            yield('%s;' % sql)

        # Build the insert statement for each row of the current table
        res = cu.execute("PRAGMA table_info('%s')" % table_name)
        column_names = [str(table_info[1]) for table_info in res.fetchall()]
        q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES("
        q += ",".join(["'||quote(" + col + ")||'" for col in column_names])
        q += ")' FROM '%(tbl_name)s'"
        query_res = cu.execute(q % {'tbl_name': table_name})
        for row in query_res:
            yield("%s;" % row[0])

元のデータベースの sqlite 接続と元のデータベースのテーブルの名前を渡すと、このジェネレーターは、新しいデータベースの sqlite オブジェクトで実行するために渡すことができるコマンドを返します。

これを行ったとき、最初にすべてのテーブルで行数をカウントし、行を実行するたびにカウンターをインクリメントINSERTして、移行の進行状況を表示できるようにしました。

于 2012-06-29T13:46:26.563 に答える