web-dev-qa-db-ja.com

一意のインデックスエラーのため、テーブルをハイパーテーブルに変換できません

Flask SQL Alchemyを次のように使用してテーブルを作成しています:

_class Price(db.Model):
    __tablename__ = "prices"
    id = db.Column(db.Integer, primary_key=True)
    country_code = db.Column(db.String(2), nullable=False)
    value = db.Column(db.Float(precision=2), nullable=False)
    start = db.Column(db.DateTime(timezone=True), nullable=False)
    end = db.Column(db.DateTime(timezone=True), nullable=False)
    price_type = db.Column(db.String(32), nullable=False)
_

次に、テーブルを作成し、次のようにしてハイパーテーブルに変換します。

_def register_timescale():
    result = db.session.execute(
        "select exists(select * from timescaledb_information.hypertable " +
        " where table_name='prices')")
    is_hypertable = [row[0] for row in result]
    if is_hypertable[0] is False:
        db.session.execute(
            "SELECT create_hypertable('prices', 'start', chunk_time_interval=>INTERVAL '1 day')")
        db.session.commit()


def create_app(app_config):
    app = Flask(__name__)

    app.config.from_object(app_config)

    register_extensions(app)
    register_blueprints(app)
    with app.app_context():
        db.create_all()
        register_timescale()
    return app
_

create_hypertable で説明されているように、prices列が_time_column_name_であるテーブルstartのハイパーテーブルを作成します。_chunk_time_interval_は1日。つまり、1つのチャンクには1日のデータが必要です

例:

1つのチャンクには、start値が_2020-04-19 00:00:00+02_であり、end値が_2020-04-20 00:00:00+02_であるデータが含まれている必要があります(下の画像の行1から24まで)。 _2020-04-20 00:00:00+02_から_2020-04-21 00:00:00+02_までの値(下の画像の25行目から48行目まで)などを含みます。

これを行うと、次のエラーが発生します。

例外が発生しました:DatabaseError(psycopg2.DatabaseError)は、列 "start"(パーティション化で使用)がないと一意のインデックスを作成できません

[SQL:SELECT create_hypertable( 'prices'、 'start'、chunk_time_interval => INTERVAL '1 day')](このエラーの背景: http://sqlalche.me/e/4xp6

次に、register_timescale()関数を次のように変更してみました。

_def register_timescale():
    result = db.session.execute(
        "select exists(select * from timescaledb_information.hypertable " +
        " where table_name='prices')")
    is_hypertable = [row[0] for row in result]
    if is_hypertable[0] is False:
        db.session.execute(
            "ALTER DATABASE mydb SET timezone TO 'Europe/Berlin'")
        db.session.execute("SELECT pg_reload_conf()")
        db.session.execute("ALTER TABLE prices ADD PRIMARY KEY (id, start)")
        db.session.execute(
            "SELECT create_hypertable('prices', (id, start), chunk_time_interval=>INTERVAL '1 day')")
        db.session.commit()
_

そして、これは私に次のエラーを与えます:

例外が発生しました:ProgrammingError(psycopg2.errors.InvalidTableDefinition)テーブル「価格」の複数の主キーは許可されていません

[SQL:ALTER TABLE価格ADD PRIMARY KEY(id、start)](このエラーの背景: http://sqlalche.me/e/f405

私のデータは次のようになります

enter image description here

誰かが私がしている間違いを指摘してもらえますか?

ありがとう

1
Junkrat

TimescaleDBでは、一意の主キーに時間ディメンション列を含める必要があります。一方、時間ディメンションとして定義できる列は1つだけです。制限については create_hypertable doc で読むことができます。

Flask SQL Alchemyには主キーが必要なので、時間ディメンション列に複合主キーを定義できます。これはstartであり、idです。 。 this doc に基づくと思います:

class Price(db.Model):
    __tablename__ = "prices"
    id = db.Column(db.Integer, primary_key=True)
    country_code = db.Column(db.String(2), nullable=False)
    value = db.Column(db.Float(precision=2), nullable=False)
    start = db.Column(db.DateTime(timezone=True), primary_key=True)
    end = db.Column(db.DateTime(timezone=True), nullable=False)
    price_type = db.Column(db.String(32), nullable=False)

その後、create_hypertableステートメントを正常に実行できるはずです。時間ディメンションとして列startのみを含める必要があります。つまり、

SELECT create_hypertable('prices', 'start', chunk_time_interval=>INTERVAL '1 day')

create_hypertablestartにデフォルトのインデックスを作成することに注意してください。アプリケーションクエリによっては、このインデックスが不要で、主キーで十分な場合があります。そのような場合、ハイパーテーブルを作成するための呼び出し中にオプションcreate_default_indexesstartに設定するか、後でDROP INDEXステートメントを実行することにより、falseのインデックスを削除できます。 ベストプラクティスセクション には詳細情報が含まれています。

2
k_rus