MySQL 5.5でPostgreSQLのような部分インデックスを作成するには


9

大きなデータがあり、一度に選択するデータの間隔が小さいので、選択は常に順序どおりになります。私はそのような目的をターゲットにしたMySQLの部分インデックスのようなPostgreSQLを実装しようとしています。部分一意制約が必要な制約と同じかどうかはわかりません。

PostgreSQL 9.4のコード

CREATE UNIQUE INDEX dir_events
    ON events (measurement_id)
    USING btree
    (eventBody)
    WHERE is_active;

MySQLでのypercubeの部分インデックスの試行

CREATE UNIQUE INDEX dir_events
    [index_type] -- TODO what here?
    ON events (measurement_id, is_active)
    [index_type] -- TODO what here?

MySQL 5.5などでPostgreSQLのような部分インデックスをどのように作成できますか?


4
MySQLは部分インデックスを実装していません。行のみを格納するis_active = TRUE(または列が1つしかない、PK ofが1つしかない)別のテーブルをデザインに追加できますdir_events
ypercubeᵀᴹ

回答:


13

MySQLも兄弟(MariaDB、Drizzleなど)も部分インデックスを実装していません。

この制限を念頭に置いてできること:

  • a)に単純な(部分的ではない)インデックスを作成し(is_active, measurement_id)ます。部分インデックスを使用するクエリで使用されます。もちろん、is_active列が3%Trueで97%Falseの場合、このインデックスは(部分インデックスより)大きくなります。しかし、それでもテーブルより小さく、これらのクエリに役立ちます。
    もう1つの制限は、UNIQUEこのソリューションではインデックスを使用できないため、制約が適用されないことです。を使用してインデックスを作成するとUNIQUE、行の一意性も適用さis_active = FALSEれます。私はあなたがそれを望んでいないと思います:

    CREATE INDEX dir_events
        ON events (is_active, measurement_id)
        USING btree ;
  • b1)(bの単純なバリエーション):の主キー列とeventsへの外部キーのみを持つ別のテーブルをデザインに追加しますevents。このテーブルにはis_active、元のテーブルでtrueになっている行のみが含まれている必要があります(これはアプリケーション/プロシージャによって強制されます)。を使用したクエリis_active = TRUEは、(WHERE条件の代わりに)そのテーブルに結合するように変更されます。
    これUNIQUEはこのソリューションでも強制されませんが、クエリは単純な結合(非常に小さなインデックスへの)のみを実行し、非常に効率的です。

    CREATE TABLE events_active
    ( event_id INT NOT NULL,         -- assuming an INT primary key on events
      PRIMARY KEY (event_id),
      FOREIGN KEY (event_id)
        REFERENCES events (event_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id)
    SELECT event_id
    FROM events
    WHERE is_active = TRUE ;
  • b2)より複雑なソリューション:テーブルとのmeasurement_id主キー列のみを使用して、デザインに別のテーブルを追加します。前の提案と同様に、このテーブルにはis_active、元のテーブルでtrueである行のみが含まれている必要があります(これは、アプリケーション/プロシージャによっても強制されます)。次に、このテーブルを使用WHERE is_active = TRUEするのは、measurement_id列だけが必要なクエリの場合のみです。より多くの列が必要なevents場合はjoin、以前と同様ににする必要があります。制約は、この溶液を用いて実施することができます。列の複製は、一貫性があるように保護することもできます(追加の一意制約と複合外部キーを使用)。
    UNIQUEmeasurement_idevents

    ALTER TABLE events
      ADD UNIQUE (event_id, measurement_id) ;
    
    CREATE TABLE events_active
    ( event_id INT NOT NULL,
      measurement_id INT NOT NULL.
      PRIMARY KEY (event_id, measurement_id),
      UNIQUE (measurement_id),
      FOREIGN KEY (event_id, measurement_id)
        REFERENCES events (event_id, measurement_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id, measurement_id)
    SELECT event_id, measurement_id
    FROM events
    WHERE is_active = TRUE ;
  • c)おそらく最も単純なもの:PostgreSQLを使用します。あなたのLinuxディストリビューション用のパッケージがあると確信しています。Postgresの最新バージョンではない可能性がありますが、7.0(またはそれ以前)で部分インデックスが追加されたため、問題は発生しません。加えて、ほとんどすべてのLinuxディストリビューションに、最新のバージョンをインストールできると確信しています。一度インストールするだけで済みます。


すばらしい答えです。Segway:部分インデックスのWikiはブログを引用しています。MySQLでは、MySQLドキュメントのどこにも記載されていない「部分インデックス」という用語は、プレフィックスインデックスを指すために使用されることがあります。それはそのブログで造られた混乱した用語です。ブログはまた、プレフィックスインデックスはより小さく/パフォーマンスが良いと主張しています。文字列の接頭辞を使用すると、深さが浅く、リーフあたりのページ数が多いbtreeが作成されるため、インデックススキャンが高速になる場合があります。シークは遅くなります。また、PostgreSQLを使用してください!私が見つけた最初のPGの言及は、v7.0のこの奇妙な操作のドキュメントですpostgresql.org/docs/7.0/partial-index.htm
Davos

0

理想的ではありませんが、フィールドに検証がある場合、値を無効にする変更を行うことができます。たとえば、不正な文字や負の数です。ソフト削除時にこの変更を行うことができ、有効な値と競合しないことがわかっています。また、ソフト削除された値が互いに衝突しないように注意する必要もあります。

1つのケースでは、一意の制約と各行の自動インクリメント整数IDを含む電子メール列がありました。ソフト削除で、実際のメールの前に「id @」(idは一意の行ID)を追加しました。 @引用されていない限り、電子メールでは許可されていません。そのため、有効な電子メールが新しい値と衝突することはなく、これが有効な電子メールと衝突することはありません。一意の整数IDにより、同じメールが複数回削除された場合でも、削除された各行が一意になることが保証されます。

これは理想的ではありませんが、問題を回避する簡単な方法です。

注:私は言及変更が追加されます、私は現在の値が最大長に近い/時すでにある場合には、追加のトリックをしなければならなかったので、一意のフィールドに文字を。それらはアプリケーション固有であるため、ここで言及する価値はありませんが、そのための回避策も知っておいてください。これは、部分インデックス機能がないことを回避する簡単な方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.