sql >> データベース >  >> RDS >> PostgreSQL

SQLでのDeltaE(CIE Lab)の計算と並べ替えのパフォーマンス

    2つのこと:1)データベースを完全に使用していないこと、および2)問題がカスタムPostgreSQL拡張機能の優れた例である。これが理由です。

    データベースをストレージとしてのみ使用し、色をフロートとして保存しています。現在の構成では、クエリのタイプに関係なく、データベースは常にすべての値をチェックする必要があります(順次スキャンを実行します)。これは、返される一致が少ない場合に、多くのIOと多くの計算を意味します。最も近いN色を見つけようとしているので、すべてのデータで計算を実行しないようにする方法にはいくつかの可能性があります。

    簡単な改善

    最も簡単なのは、計算をデータのより小さなサブセットに制限することです。コンポーネントの違いが大きいほど、違いは大きくなると考えられます。結果が常に不適切であるコンポーネント間の安全な違いを見つけることができる場合は、btreeインデックスで範囲WHEREを使用して、それらの色を完全に除外できます。ただし、L * a * b色空間の性質上、これにより結果が悪化する可能性があります。

    最初にインデックスを作成します:

    CREATE INDEX color_lab_l_btree ON color USING btree (lab_l);
    CREATE INDEX color_lab_a_btree ON color USING btree (lab_a);
    CREATE INDEX color_lab_b_btree ON color USING btree (lab_b);
    

    次に、色のみをフィルタリングするWHERE句を含めるようにクエリを調整しました。ここで、コンポーネントのいずれかが最大20で異なります。

    更新: もう一度見てみると、20の制限を追加すると、結果が悪化する可能性が非常に高くなります。これは、空間内に少なくとも1つのポイントが見つかったためです。これは、当てはまります。:

    SELECT 
        c.rgb_r, c.rgb_g, c.rgb_b,
        DELTA_E_CIE2000(
            25.805780252087963, 53.33446637366859, -45.03961353720049, 
            c.lab_l, c.lab_a, c.lab_b,
            1.0, 1.0, 1.0) AS de2000
    FROM color c 
    WHERE 
        c.lab_l BETWEEN 25.805780252087963 - 20 AND 25.805780252087963 + 20 
        AND c.lab_a BETWEEN 53.33446637366859 - 20 AND 53.33446637366859 + 20 
        AND c.lab_b BETWEEN -45.03961353720049 - 20 AND -45.03961353720049 + 20 
    ORDER BY de2000 ;
    

    スクリプトを使用してテーブルに100000のランダムな色を入力し、テストしました:

    インデックスなしの時間:44006,851ミリ秒

    インデックスと範囲クエリの時間:1293,092ミリ秒

    このWHERE句をdelta_e_cie1976_queryに追加できます また、私のランダムデータでは、クエリ時間が約110ミリ秒から約22ミリ秒に短縮されます。

    ところで:私は経験的に20という数字を取得しました:10で試しましたが、380レコードしか取得できませんでした。これは少し低いようで、制限が100であるため、いくつかのより良いオプションが除外される可能性があります。最も近い一致がそこにあることを確認してください。 DELTA_E_CIE2000またはL*a * b *色空間を詳細に調べなかったため、実際にそれを実現するには、さまざまなコンポーネントに沿ってしきい値を調整する必要があるかもしれませんが、興味のないデータを除外するという原則は当てはまります。

    Delta ECIE2000をCで書き直します

    すでに述べたように、Delta E CIE 2000は複雑で、SQLでの実装にはかなり適していません。現在、私のラップトップでは1回の呼び出しで約0.4ミリ秒を使用しています。 Cで実装すると、これが大幅に高速化されます。 PostgreSQLはデフォルトのコストをSQL関数に100として割り当て、C関数に1として割り当てます。これは実際の経験に基づいていると思います。

    更新: これも私のかゆみの1つを傷つけるので、CのcolormathモジュールからのDeltaE関数をPostgreSQL拡張機能として再実装しました。これは PGXN 。これにより、10万レコードのテーブルからすべてのレコードをクエリすると、CIE2000の約150倍のスピードアップが見られます。

    このC関数を使用すると、100k色で147ミリ秒から160ミリ秒のクエリ時間が得られます。 WHEREを追加すると、クエリ時間は約20ミリ秒になります。これは、私にとってはかなり許容できるようです。

    最高の、しかし高度なソリューション

    ただし、問題は3次元空間でのN最近傍検索であるため、PostgreSQLにあるK最近傍インデックスを使用できますバージョン9.1以降

    これを機能させるには、L * a *b*コンポーネントをキューブ 。この拡張機能は、距離演算子をまだサポートしていません(作業中です )、ただし、サポートされている場合でも、デルタE距離はサポートされないため、C拡張として再実装する必要があります。

    これは、GiSTインデックス演算子クラス( btree_gistPostgreSQL拡張機能 )を実装することを意味します。 in contribはこれを行います)デルタE距離に応じたインデックス付けをサポートします。良い点は、DeltaEのバージョンごとに異なる演算子を使用できることです。 <-> Delta E CIE2000および<#>の場合 Delta E CIE 1976の場合、クエリは 本当に高速 になります。 Delta ECIE2000でも小さなLIMITの場合。

    結局、それはあなたの(ビジネス)要件と制約が何であるかに依存するかもしれません。




    1. 同じ名前のエンティティ、常に最初のIDに挿入

    2. 2018年のレビュー:見逃した可能性のある7つのMariaDBマイルストーン

    3. SQLServerで条件が満たされた場合にのみ起動するトリガー

    4. SELECT *[columnAを除く]FROM tableAを使用して列を除外しますか?