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

Postgres文字列配列で大文字と小文字を区別しないインデックスを作成する

    @Saurabh Nanda:投稿したものと同様に、次のようにvarchar配列を小文字に変換する簡単な関数を作成することもできます。

    CREATE OR REPLACE FUNCTION array_lowercase(varchar[]) RETURNS varchar[] AS
    $BODY$
      SELECT array_agg(q.tag) FROM (
        SELECT btrim(lower(unnest($1)))::varchar AS tag
      ) AS q;
    $BODY$
      language sql IMMUTABLE;
    

    スペースのタグもトリミングしていることに注意してください。これはあなたにとって必要ではないかもしれませんが、私は通常一貫性のために必要です。

    テスト:

    SELECT array_lowercase(array['Hello','WOrLD']);
     array_lowercase 
    -----------------
     {hello,world}
    (1 row)
    

    Saurabhが指摘したように、次にGINインデックスを作成できます:

    CREATE INDEX ix_tags ON tagtable USING GIN(array_lowercase(tags));
    

    そしてクエリ:

    SELECT * FROM tagtable WHERE ARRAY['mytag'::varchar] && array_lowercase(tags);
    

    更新: WHILEのパフォーマンス vs array_agg / unnest

    100K10要素のテーブルを作成しましたtext[] 配列(12文字のランダムな大文字と小文字が混在する文字列)と各関数のテスト。

    array_agg / unnest関数が返されました:

    EXPLAIN ANALYZE VERBOSE SELECT array_lowercase(data) FROM test;
                                                           QUERY PLAN                                                       
    ------------------------------------------------------------------------------------------------------------------------
     Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=0.320..3041.292 rows=100000 loops=1)
       Output: array_lowercase((data)::character varying[])
     Total runtime: 3174.690 ms
    (3 rows)
    

    WHILE関数が返されました:

    EXPLAIN ANALYZE VERBOSE SELECT array_lowercase_while(data) FROM test;
                                                           QUERY PLAN                                                       
    ------------------------------------------------------------------------------------------------------------------------
     Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=5.128..4356.647 rows=100000 loops=1)
       Output: array_lowercase_while((data)::character varying[])
     Total runtime: 4485.226 ms
    (3 rows)
    

    更新2: FOREACH vs. WHILE 最後の実験として、WHILE関数をFOREACHを使用するように変更しました:

    CREATE OR REPLACE FUNCTION array_lowercase_foreach(p_input varchar[]) RETURNS varchar[] AS $BODY$
    DECLARE
        el text;
        r varchar[];
    BEGIN
        FOREACH el IN ARRAY p_input LOOP
            r := r || btrim(lower(el))::varchar;
        END LOOP;
        RETURN r;
    END;
    $BODY$
      language 'plpgsql'
    

    結果はWHILEと同様のようでした :

    EXPLAIN ANALYZE VERBOSE SELECT array_lowercase_foreach(data) FROM test;
                                                           QUERY PLAN                                                       
    ------------------------------------------------------------------------------------------------------------------------
     Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=0.707..4106.867 rows=100000 loops=1)
       Output: array_lowercase_foreach((data)::character varying[])
     Total runtime: 4239.958 ms
    (3 rows)
    

    私のテストは決して厳密ではありませんが、各バージョンを何度も実行し、その数が代表的なものであることがわかりました。これは、SQLメソッド(array_agg / unnest)が最速であることを示唆しています。



    1. PHPのビットフラグのベストプラクティス

    2. クエリを介してMySQLでデータベース構造を取得する方法

    3. MY SQLの列のグループに行番号が必要ですか?

    4. 2つの変動する日付の間に無料の車両を見つけようとしています