1

パーティション間で行を分散するために Postgres (バージョン 13.2) で使用されるカスタム ハッシュ関数を作成したいと考えています。問題は、現在のソリューションでは Postgres がパーティションのプルーニングを使用していないことです。これが私のコードです:

-- dummy hash function
CREATE OR REPLACE FUNCTION partition_custom_bigint_hash(value BIGINT, seed
BIGINT)
RETURNS BIGINT AS $$
    SELECT value;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;

-- operator
CREATE OPERATOR CLASS partition_custom_bigint_hash_op
    FOR TYPE int8
    USING hash AS
    OPERATOR 1 =,
    FUNCTION 2 partition_custom_bigint_hash(BIGINT, BIGINT);

-- table partitioned by hash with custom operator
CREATE TABLE sample(part_id BIGINT) PARTITION BY hash(part_id partition_custom_bigint_hash_op);
CREATE TABLE sample_part_1 PARTITION OF SAMPLE FOR VALUES WITH (modulus 3, remainder 0);
CREATE TABLE sample_part_2 PARTITION OF SAMPLE FOR VALUES WITH (modulus 3, remainder 1);
CREATE TABLE sample_part_3 PARTITION OF SAMPLE FOR VALUES WITH (modulus 3, remainder 2);

ここで、パーティションのプルーニングが有効になっており、正しく機能していることを確認します。

SHOW enable_partition_pruning;
--  enable_partition_pruning
-- --------------------------
--  on

EXPLAIN * FROM sample WHERE part_id = 1::BIGINT;
--                               QUERY PLAN                              
-- ----------------------------------------------------------------------
--  Seq Scan on sample_part_1 sample  (cost=0.00..38.25 rows=11 width=8)
--    Filter: (part_id = '1'::bigint)
-- (2 rows)

したがって、条件を使用すると問題part_id=1::BIGINTなく動作しますが、BIGINT へのキャストをスキップすると、次のようになります。

EXPLAIN SELECT * FROM sample WHERE part_id = 1;
--                                   QUERY PLAN
-- ------------------------------------------------------------------------------
--  Append  (cost=0.00..101.36 rows=33 width=8)
--    ->  Seq Scan on sample_part_1 sample_1  (cost=0.00..33.73 rows=11 width=8)
--          Filter: (part_id = 1)
--    ->  Seq Scan on sample_part_2 sample_2  (cost=0.00..33.73 rows=11 width=8)
--          Filter: (part_id = 1)
--    ->  Seq Scan on sample_part_3 sample_3  (cost=0.00..33.73 rows=11 width=8)
--          Filter: (part_id = 1)

part_id=1質問: パーティションのプルーニングを条件との両方で機能させるには、何を変更する必要がありpart_id=1::BIGINTますか?

4

1 に答える 1

3

bigint左側にいくつかの等価演算子があります。

SELECT oid,
       oprcode::regproc AS function,
       oprright::regtype AS right_side
FROM pg_operator
WHERE oprname = '='
  AND oprleft = 'bigint'::regtype;

 oid  | function | right_side 
------+----------+------------
  410 | int8eq   | bigint
  416 | int84eq  | integer
 1868 | int82eq  | smallint
(3 rows)

2 番目のクエリはこれらの演算子の 2 番目を使用しますが、その演算子はカスタム演算子ファミリに属していないため、パーティションのプルーニングは行われません。

のこのコメントを参照してmatch_clause_to_partition_keyくださいsrc/backend/partitioning/partprune.c:

/*
 * See if the operator is relevant to the partitioning opfamily.
 *
 * Normally we only care about operators that are listed as being part
 * of the partitioning operator family.  But there is one exception:
 * the not-equals operators are not listed in any operator family
 * whatsoever, but their negators (equality) are.  We can use one of
 * those if we find it, but only for list partitioning.
 *
 * Note: we report NOMATCH on failure, in case a later partkey has the
 * same expression but different opfamily.  That's unlikely, but not
 * much more so than duplicate expressions with different collations.
 */

必要な演算子を含む演算子ファミリを作成します。

CREATE FUNCTION partition_custom_hash(value int8, seed int8) RETURNS int8
   AS 'SELECT value' LANGUAGE SQL IMMUTABLE PARALLEL SAFE;

CREATE FUNCTION partition_custom_hash(value int4, seed int4) RETURNS int8
   AS 'SELECT value::int8' LANGUAGE SQL IMMUTABLE PARALLEL SAFE;

CREATE FUNCTION partition_custom_hash(value int2, seed int2) RETURNS int8 
   AS 'SELECT value::int8' LANGUAGE SQL IMMUTABLE PARALLEL SAFE;

CREATE OPERATOR FAMILY partition_custom_integer_hash_ops USING hash;

CREATE OPERATOR CLASS partition_custom_int8_hash_ops FOR TYPE int8 USING hash
   FAMILY partition_custom_integer_hash_ops AS
   OPERATOR 1 = (int8, int8),
   FUNCTION 2 partition_custom_hash(int8, int8);

CREATE OPERATOR CLASS partition_custom_int4_hash_ops FOR TYPE int4 USING hash
   FAMILY partition_custom_integer_hash_ops AS
   OPERATOR 1 = (int8, int4),
   FUNCTION 2 partition_custom_hash(int4, int4);

CREATE OPERATOR CLASS partition_custom_int2_hash_ops FOR TYPE int2 USING hash 
   FAMILY partition_custom_integer_hash_ops AS 
   OPERATOR 1 = (int8, int2),
   FUNCTION 2 partition_custom_hash(int2, int2);

次に、を使用するpartition_custom_int8_hash_opsと、必要に応じて機能するはずです。

于 2021-03-02T15:27:33.417 に答える