
рдЕрдВрддрд┐рдо PGConf.Russia рдореЗрдВ, MobilityDB рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд░рд┐рдкреЛрд░реНрдЯ рдереА, рдФрд░ рдЖрдВрджреНрд░реЗрдИ рдмреЛрд░реЛрдбрд┐рди рдиреЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рд╕реВрдЪрдХрд╛рдВрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдХрд┐рдпрд╛ рдерд╛ ред
рдореИрдВ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рд╕рд╛рде рд╡рд┐рд╖рдп рдХреЛ рдЬрд╛рд░реА рд░рдЦреВрдВрдЧрд╛ , рдЬреЛ рдХрд┐ рд╣рд╛рдИрд▓рд╛рдб рдХрдк 2018 рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдП рдЧрдП рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдХреЛрдб GithHub рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИред рд╣рдмрд▓ рдкрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмреНрд▓реИрдХрдорд╛рд╕реНрдЯрд░ рдХрд╛ рдПрдХ рд▓реЗрдЦ рд╣реИред рдПрдХреНрд╕рдЯреЗрдВрд╢рди btree рдФрд░ GIN рдЗрдВрдбреЗрдХреНрд╕ рдХреЗ рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рджреЛ рдкреНрд░рдХрд╛рд░ рдЬреЛрдбрд╝рддрд╛ рд╣реИред
рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдпреЛрдЬрдирд╛:
CREATE TABLE accounts ( id INTEGER PRIMARY KEY, email VARCHAR(100) UNIQUE, fname SMALLINT, sname VARCHAR(50), phone VARCHAR(16) UNIQUE, birth TIMESTAMP NOT NULL, country SMALLINT, city SMALLINT, email_domain SMALLINT, joined TIMESTAMP NOT NULL, status status, sex sex NOT NULL, interests SMALLINT[], premium tsrange, likes_ids INTEGER[], likes_tss INTEGER[], CHECK ( joined >= '01.01.2011'::timestamp ), CHECK ( joined <= '01.01.2018'::timestamp ) ); CREATE INDEX IF NOT EXISTS interests_ids_index ON accounts USING GIN(interests); 
рд░рд┐рдХреЙрд░реНрдб рдХреА рд╕рдВрдЦреНрдпрд╛ 1,300,000 рд╣реИ , рдФрд░ рдмреНрдпрд╛рдЬ рдХреЗ рд╕рдВрдмрдВрдз рдХрд╛ рдЖрдХрд╛рд░:
| рд╕рдВрдмрдВрдз | рдЖрдХрд╛рд░ | 
|---|
| рдЦрд╛рддреЛрдВ | 598 рдПрдордмреА | 
| accounts_email_key | 54 рдПрдордмреА | 
| accounts_phone_key | 32 рдПрдордмреА | 
| accounts_pkey | 28 рдПрдордмреА | 
| interests_ids_index | 8072 рдХреЗрдмреА | 
рдЕрдВрддрд┐рдо рд╕рд░реНрдХрд┐рдЯ:
 CREATE UNLOGGED TABLE accounts ( id INTEGER PRIMARY KEY, email VARCHAR(100) UNIQUE, fname SMALLINT, sname VARCHAR(50), phone phone UNIQUE, birth TIMESTAMP NOT NULL, country SMALLINT, city SMALLINT, email_domain SMALLINT, joined TIMESTAMP NOT NULL, status status, sex sex NOT NULL, interests bit128, premium tsrange, likes_ids INTEGER[], likes_tss INTEGER[], CHECK ( joined >= '01.01.2011'::timestamp ), CHECK ( joined <= '01.01.2018'::timestamp ) ); 
рдЖрдпрд╛рдо:
| рд╕рдВрдмрдВрдз | рдкреБрд░рд╛рдирд╛ рдЖрдХрд╛рд░ | рдирдпрд╛ рдЖрдХрд╛рд░ | 
|---|
| рдЦрд╛рддреЛрдВ | 598 рдПрдордмреА | 579 рдПрдордмреА | 
| accounts_phone_key | 32 рдПрдордмреА | 28 рдПрдордмреА | 
| accounts_pkey | 28 рдПрдордмреА | 28 рдПрдордмреА | 
| interests_ids_index | 8072 рдХреЗрдмреА | 8072 рдХреЗрдмреА | 
рджреЛ рдкреНрд░рдХрд╛рд░ рдЬреЛрдбрд╝реЗ рдЧрдП: рдлреЛрди рдФрд░ рдмрд┐рдЯ128 ред
рдлрд╝реЛрди
рдлреЛрди рдирдВрдмрд░ 8 (929) 5481819 рд╣реИ , рдЖрда рдХреЛ рдЦрд╛рд░рд┐рдЬ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдСрдкрд░реЗрдЯрд░ рдХреЛрдб 10 рдмрд┐рдЯреНрд╕, рд╕рдВрдЦреНрдпрд╛ 24 рдмрд┐рдЯреНрд╕ рдореЗрдВ рдлрд┐рдЯ рдмреИрдарддрд╛ рд╣реИ, рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ 5 рдмрд╛рдЗрдЯреНрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдореЗрдореЛрд░реА рдореЗрдВ рдбреЗрдЯрд╛ рд╕рдВрд░реЗрдЦрдг рдХреЗ рдХрд╛рд░рдг рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╕рдВрдЦреНрдпрд╛ рдирд╣реАрдВ рд╣реИред 5, 6 рдпрд╛ 8 рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдХреИрд╕реЗ рдлрд┐рдЯ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕ рд╕рд╡рд╛рд▓ рдкрд░, рдХреЗрд╡рд▓ рдкрд░реАрдХреНрд╖рдг рд╣реА рдЬрд╡рд╛рдм рджреЗ рд╕рдХрддреЗ рд╣реИрдВред
рдпрджрд┐ рдЖрдк рдкреНрд░рд▓реЗрдЦрди рд╕реЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдереЛрдбрд╝реА рдЬрд░реВрд░рдд рд╣реИред рдкрд░рд┐рднрд╛рд╖рд┐рдд рдкреНрд░рдХрд╛рд░:
 class Phone : public PAllocNew<Phone> { public: bool fromCString(char* str) noexcept; char* toCString() const noexcept; int code() const noexcept; bool operator==(const Phone& b) const noexcept; bool operator<(const Phone& b) const noexcept; bool operator<=(const Phone& b) const noexcept; bool operator>(const Phone& b) const noexcept; bool operator>=(const Phone& b) const noexcept; private: uint64_t m_data = 0; }; #define GETARG_PHONE(x) reinterpret_cast<Phone*>(PG_GETARG_POINTER(x)) 
PAllocNew рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ new :
 template<typename T> class PAllocNew { public: static void* operator new(std::size_t count, const std::nothrow_t& tag) { return palloc(count); } }; 
рдкреИрд▓реЛрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрд╡рдВрдЯрд┐рдд рдореЗрдореЛрд░реА рдХреЛ рд▓реЗрдирджреЗрди рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░ рдореБрдХреНрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред I / O рдХрд╛рд░реНрдп рдЬреЛрдбрд╝реЗрдВ:
 Datum phone_in(PG_FUNCTION_ARGS) { char* str = PG_GETARG_CSTRING(0); auto v = new(std::nothrow) Phone; if (!v->fromCString(str)) { ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg( "invalid input syntax for phone: \"%s\"", str ))); } PG_RETURN_POINTER(v); } Datum phone_out(PG_FUNCTION_ARGS) { const auto phone = GETARG_PHONE(0); PG_RETURN_CSTRING(phone->toCString()); } 
рдФрд░ рдкрдВрдЬреАрдХрд░рдг рдкреНрд░рдХрд╛рд░:
 CREATE TYPE phone; CREATE OR REPLACE FUNCTION phone_in ( cstring ) RETURNS phone AS 'libhighloadcup' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION phone_out ( phone ) RETURNS cstring AS 'libhighloadcup' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE TYPE phone ( INTERNALLENGTH = 8, INPUT = phone_in, OUTPUT = phone_out, ALIGNMENT = int4, COLLATE TRUE ); 
рдХреНрдпреЛрдВрдХрд┐ рдирдП рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЖрдХрд╛рд░ 8 рдмрд╛рдЗрдЯреНрд╕ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИ, рдЗрд╕реЗ рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдореВрд▓реНрдп рджреНрд╡рд╛рд░рд╛ рдкреНрд░реЗрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдЖрдкрдХреЛ CREATE TYPE рдореЗрдВ PASSEDBYVALUE рдзреНрд╡рдЬ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдпрд╛ LIKE рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
 CREATE TYPE phone ( INPUT = phone_in, OUTPUT = phone_out, LIKE = int8, COLLATE TRUE ); 
рдЗрд╕рдХреЗ рдмрд╛рдж PASSEDBYVALUE ALIGNMENT PASSEDBYVALUE ALIGNMENT рдФрд░ PASSEDBYVALUE рд╡рд┐рд░рд╛рд╕рдд PASSEDBYVALUE рдорд┐рд▓рд╛ рд╣реИред
btree рд╕реВрдЪрдХрд╛рдВрдХ
рд╡рд┐рд╢рд┐рд╖реНрдЯ рдмреА-рдЯреНрд░реА рдЗрдВрдбреЗрдХреНрд╕ рдмрдирд╛рдХрд░ рдХреНрд╖реЗрддреНрд░ рдХреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдСрдкрд░реЗрдЯрд░реЛрдВ рдФрд░ рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреА рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
| рдСрдкрд░реЗрдЯрд░ | рд╕рдВрдЦреНрдпрд╛ | 
|---|
| рдХрдо | 1 | 
| рд╕реЗ рдХрдо рдпрд╛ рдмрд░рд╛рдмрд░ | 2 | 
| рд╣реИ | 3 | 
| рд╕реЗ рдЕрдзрд┐рдХ рдпрд╛ рдмрд░рд╛рдмрд░ | 4 | 
| рдмрдбрд╝рд╛ | 5 | 
| рд╕рдорд╛рд░реЛрд╣ | рд╕рдВрдЦреНрдпрд╛ | 
|---|
| рд╣реИ | 1 | 
 CREATE OPERATOR = ( PROCEDURE = phone_equal, LEFTARG = phone, RIGHTARG = phone, COMMUTATOR = =, NEGATOR = != ); CREATE OPERATOR < ( PROCEDURE = phone_lt, LEFTARG = phone, RIGHTARG = phone, NEGATOR = > ); CREATE OPERATOR <= ( PROCEDURE = phone_le, LEFTARG = phone, RIGHTARG = phone ); CREATE OPERATOR >= ( PROCEDURE = phone_ge, LEFTARG = phone, RIGHTARG = phone ); CREATE OPERATOR > ( PROCEDURE = phone_gt, LEFTARG = phone, RIGHTARG = phone, NEGATOR = < ); CREATE OPERATOR CLASS btree_phone_ops DEFAULT FOR TYPE phone USING btree AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 phone_equal_internal ( phone, phone ); 
рдСрдкрд░реЗрдЯрд░ bool рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рдФрд░ phone_equal_internal int:
 Datum phone_equal_internal(PG_FUNCTION_ARGS) { const auto a = GETARG_PHONE(0); const auto b = GETARG_PHONE(1); if (*a < *b) { PG_RETURN_INT32(-1); } if (*a > *b) { PG_RETURN_INT32(1); } PG_RETURN_INT32(0); } 
рдпрд╣ рд╕рдм рдбреЗрдЯрд╛ рдореЗрдВ рдереЛрдбрд╝реА рдХрдореА рдЖрдИ:
| рд╕рдВрдмрдВрдз | рдЖрдХрд╛рд░ | diff | 
|---|
| рдЦрд╛рддреЛрдВ | 595 рдПрдордмреА | 3 рдПрдордмреА | 
| accounts_phone_key | 28 рдПрдордмреА | 4 рдПрдордмреА | 
533,289 рд╕рдВрдЦреНрдпрд╛ рд╡рд╛рд▓реЗ рдЦрд╛рддреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛, рдЬреЛ рдХрд┐ 41% рд╣реИред рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп рдХрдо рд╕реЗ рдХрдо рдХреЛрдИ рд╕реНрдЯреНрд░рд┐рдВрдЧ рддреБрд▓рдирд╛ рдирд╣реАрдВ рд╣реИред
bit128
рдореИрдВ рдЪреМрд░рд╛рд╣реЗ рдХреЗ рд╕рдВрдЪрд╛рд▓рди (&&), рдШрдЯрдирд╛ (<@) рдХреЗ рд╕рд╛рде рдФрд░ GIN рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд╛ рдХреНрд╖реЗрддреНрд░ рд░рдЦрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдпрд╣ 96 рдмрд┐рдЯ рдкрд░реНрдпрд╛рдкреНрдд рдерд╛, рд▓реЗрдХрд┐рди рдПрдХ рд╕рд░рд▓ рдкрде рдкрд░ рдЪрд▓рд╛ рдЧрдпрд╛ рдФрд░ uint128 рд▓реЗ рд▓рд┐рдпрд╛ред
 class BitSet128: public PAllocNew<BitSet128> { public: bool haveIntersection(const BitSet128& b) const noexcept; bool contains(const BitSet128& b) const noexcept; bool operator==(const BitSet128& b) const noexcept; bool operator<(const BitSet128& b) const noexcept; bool operator>(const BitSet128& b) const noexcept; bool fromCString(char* str) noexcept; char* toCString() const noexcept; std::vector<uint8_t> keys() const; private: uint128 m_bits = 0; }; #define GETARG_BIT128(x) reinterpret_cast<BitSet128*>(PG_GETARG_POINTER(x)) 
рдкреНрд░рдХрд╛рд░ рдФрд░ рд╕рдВрдЪрд╛рд▓рди рдХрд╛ рдкрдВрдЬреАрдХрд░рдг:
 CREATE TYPE bit128 ( INTERNALLENGTH = 16, INPUT = bit128_in, OUTPUT = bit128_out, ALIGNMENT = int4 ); CREATE OPERATOR = ( PROCEDURE = bit128_equal, LEFTARG = bit128, RIGHTARG = bit128, COMMUTATOR = =, NEGATOR = != ); CREATE OPERATOR && ( PROCEDURE = bit128_intersection, LEFTARG = bit128, RIGHTARG = bit128 ); CREATE OPERATOR @> ( PROCEDURE = bit128_containts, LEFTARG = bit128, RIGHTARG = bit128 ); 
рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдЙрд▓реНрдЯрд╛ рд╕реВрдЪрдХрд╛рдВрдХ / GIN
Egor Rogov erogov рдиреЗ PostgreSQL - 7 рдореЗрдВ рд▓реЗрдЦ рдЗрдВрдбреЗрдХреНрд╕ рдореЗрдВ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬ рдореЗрдВ GIN рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрд╛, рдЗрд╕реЗ рдкреВрд░реНрдг-рдкрд╛рда рдЦреЛрдЬ рдХрд╛рд░реНрдп рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ред GIN рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА рдбреЙрдХреНрдпреВрдореЗрдВрдЯреЗрд╢рди рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ 4 рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ:
рдЕрдиреБрдХреНрд░рдорд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
 Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags) 
рдЕрдиреБрд░реЛрдзрд┐рдд рдорд╛рди рдХреЗ рд▓рд┐рдП рдХреБрдВрдЬрд┐рдпрд╛рдБ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ:
 Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data, bool **nullFlags, int32 *searchMode) 
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдкреНрд░рд╢реНрди рдореЗрдВ:
 SELECT * FROM test WHERE a && ARRAY[1, 2, 3] 
extractQuery рдХреЛ ARRAY[1, 2, 3] рд╕рд░рдгреА рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдХреБрдВрдЬрд┐рдпрд╛рдБ 1, 2, 3 рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
рдЬрд╛рдБрдЪрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдорд╛рди рдХреНрд╡реЗрд░реА рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ:
 bool consistent(bool check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], bool *recheck, Datum queryKeys[], bool nullFlags[]) 
рдЪреВрдВрдХрд┐ рдирд┐рдХрд╛рд▓реЗ рдЧрдП рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдЦреЛрдЬ рдЯреНрд░реА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдореЗрдВ рдПрдХ рддреБрд▓рдирд╛ рдлрд╝рдВрдХреНрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ:
 int compare(Datum a, Datum b) 
рдПрдкреАрдЖрдИ рдмреЗрдорд╛рдиреА рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╣ рд╕рдм рдХреБрдЫ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдХрд╛рдо рдореЗрдВ рдЖ рд╕рдХрддрд╛ рд╣реИред рдЖрдЗрдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝реЗрдВред рдореБрдЦреНрдп рдирд┐рд╖реНрдХрд░реНрд╖рдг:
 Datum gin_extract_value_bit128(PG_FUNCTION_ARGS) { auto bitset = GETARG_BIT128(0); const auto bits = bitset->keys(); int32* nentries = (int32*) PG_GETARG_POINTER(1); *nentries = bits.size(); Datum* entries = NULL; entries = (Datum*) palloc(sizeof(Datum) * bits.size()); for (int i = 0; i < bits.size(); ++i) { entries[i] = DatumGetInt16(bits[i]); } PG_RETURN_POINTER(entries); } 
рдЖрдЙрдЯрдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░ nentries рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд▓рд┐рдЦреЗрдВ рдФрд░ рдХреБрдВрдЬреА entries рдХреА рдПрдХ рд╕рд░рдгреА рд▓реМрдЯрд╛рдПрдВред рдкреНрд░рдореБрдЦ рддреБрд▓рдирд╛:
 Datum bit128_cmp(PG_FUNCTION_ARGS) { const auto a = PG_GETARG_INT16(0); const auto b = PG_GETARG_INT16(1); if (a < b) { PG_RETURN_INT32(-1); } if (a > b) { PG_RETURN_INT32(1); } PG_RETURN_INT32(0); } 
рдЗрдВрдбреЗрдХреНрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдпреЗ рджреЛ рдХрд╛рд░реНрдп рдкрд░реНрдпрд╛рдкреНрдд рд╣реИрдВред рд╕реВрдЪрдХрд╛рдВрдХ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬ рдХрд░рдиреЗ рдкрд░ рдЕрдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдиреБрд░реЛрдз рд╕реЗ рдХреБрдВрдЬрд┐рдпрд╛рдБ рдирд┐рдХрд╛рд▓рдирд╛:
 Datum gin_extract_query_bit128(PG_FUNCTION_ARGS) { const auto a = GETARG_BIT128(0); int32* nentries = (int32*) PG_GETARG_POINTER(1); StrategyNumber strategy = PG_GETARG_UINT16(2); int32* searchMode = (int32*) PG_GETARG_POINTER(6); Datum* res = nullptr; const auto keys = a->keys(); *nentries = keys.size(); res = (Datum*) palloc(sizeof(Datum) * keys.size()); for (int i = 0; i < keys.size(); ++i) { res[i] = DatumGetInt16(keys[i]); } switch (strategy) { case RTOverlapStrategyNumber:  
рдкрд╣рд▓рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рдорд╛рди рдСрдкрд░реЗрдЯрд░ рдХреЗ рджрд╛рдИрдВ рдУрд░ рд╕реЗ рдЧреБрдЬрд░рддрд╛ рд╣реИ, рддреАрд╕рд░рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рд░рдгрдиреАрддрд┐ (рдСрдкрд░реЗрдЯрд░) рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬ рдХреА рдЬрд╛рддреА рд╣реИред рдЦреЛрдЬ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдмреЗрд╣рддрд░ рдкрд░рд┐рдЪрд┐рдд рд╣реИред рдЕрдиреБрдкрд╛рд▓рди рд╕рдорд╛рд░реЛрд╣:
 Datum gin_bit128_consistent(PG_FUNCTION_ARGS) { bool* check = (bool*) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); int32 nkeys = PG_GETARG_INT32(3); bool* recheck = (bool*) PG_GETARG_POINTER(5); bool res = true; switch (strategy) { case RTOverlapStrategyNumber:  
рдпрджрд┐ рдЕрдиреБрдХреНрд░рдорд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рд░рдгрдиреАрддрд┐ рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдХреНрд╡реЗрд░реА рдСрдкрд░реЗрдЯрд░ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рддрд╛ true рддреЛ true ред рдЪреЗрдХ рдРрд░реЗ рдХреА рд▓рдВрдмрд╛рдИ рд▓рдВрдмреА рд╣реЛрддреА рд╣реИ, рдЬреЛ рдХрд┐ gin_extract_query_bit128 рджреНрд╡рд╛рд░рд╛ рджреА рдЧрдИ рдЪрд╛рдмрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рдореЗрд▓ рдЦрд╛рддреА рд╣реИред рдЪреЗрдХрд┐рдВрдЧ check[i] = true рдЕрд░реНрде рд╣реИ рдХрд┐ gin_extract_query_bit128 рд╕реЗ i-th рдХреБрдВрдЬреА рдЕрдиреБрдХреНрд░рдорд┐рдд рд╡рд╕реНрддреБ рдореЗрдВ рдореМрдЬреВрдж рд╣реИред рдпрд╣ рдкрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрдпреЛрдВрдХрд┐ GIN рдореЗрдВ рд╣рдо рд╕реНрд╡рдпрдВ рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдлрд┐рд░ рдкреНрд░рд╡реЗрд╢ рд░рдгрдиреАрддрд┐ рдХреЗ рд▓рд┐рдП рд╣рдо рд╕рд╣реА рдкрд░ рд░реАрдЪреЗрдХ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдкрд░рд┐рдгрд╛рдо рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдСрдкрд░реЗрдЯрд░ рдХреЛ рдмреБрд▓рд╛рдПрдЧрд╛ред рдСрдкрд░реЗрдЯрд░ рд╡рд░реНрдЧ:
 CREATE OR REPLACE FUNCTION gin_extract_value_bit128 ( bit128, internal, internal) RETURNS internal AS 'libhighloadcup' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION gin_extract_query_bit128(bit128, internal, int2, internal, internal) RETURNS internal AS 'libhighloadcup' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION gin_bit128_consistent(internal, int2, anyelement, int4, internal, internal) RETURNS bool AS 'libhighloadcup' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE OPERATOR CLASS bit128_ops DEFAULT FOR TYPE bit128 USING gin AS OPERATOR 3 &&, OPERATOR 6 =, OPERATOR 7 @>, FUNCTION 1 bit128_cmp (int2, int2 ), FUNCTION 2 gin_extract_value_bit128(bit128, internal, internal), FUNCTION 3 gin_extract_query_bit128(bit128, internal, int2, internal, internal), FUNCTION 4 gin_bit128_consistent(internal, int2, anyelement, int4, internal, internal), STORAGE int2; 
рд╕реНрдЯреЛрд░реЗрдЬ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛ , рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдХреБрдВрдЬреА рдХреЗ рд▓рд┐рдП рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдбреЗрдЯрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдбрд┐рд╕реНрдХ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдХреНрдпрд╛ рд╣реИ:
| рд╕рдВрдмрдВрдз | рдкреБрд░рд╛рдирд╛ рдЖрдХрд╛рд░ | рдирдпрд╛ рдЖрдХрд╛рд░ | diff | 
|---|
| рдЦрд╛рддреЛрдВ | 595 рдПрдордмреА | 579 рдПрдордмреА | 16 рдПрдордмреА | 
| interests_ids_index | 8072 рдХреЗрдмреА | 8072 рдХреЗрдмреА |  | 
рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдкрд░рд┐рдгрд╛рдо рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдмрд╛рд░реАрдХрд┐рдпрд╛рдВ рд╣реИрдВ:
- рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рднреМрддрд┐рдХ рднрдВрдбрд╛рд░рдг;
- рдбреЗрдЯрд╛ рд╡рд┐рддрд░рдгред
рд╕рднреА рдмрдирд╛рдП рдЧрдП рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЖрдХрд╛рд░ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЙрдирдХреЗ рд▓рд┐рдП PLAIN рд╕рдВрдЧреНрд░рд╣рдг рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдВрдкреАрдбрд╝рди рдФрд░ рдЕрд▓рдЧ рднрдВрдбрд╛рд░рдг рдЙрди рдкрд░ рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЪрд░-рд▓рдВрдмрд╛рдИ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдЕрд░реНрд░реЗ рдФрд░ рддрд╛рд░ рдЯреЛрд╕реНрдЯ рд╕реЗ рд╣реЛрдХрд░ рдЧреБрдЬрд░рддреЗ рд╣реИрдВред рд╣рд╛рдВ, рднрдВрдбрд╛рд░рдг рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдУрд╡рд░рд╣реЗрдб рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрдкреАрдбрд╝рди рднреА рд╣реИред
рд╣рд┐рддреЛрдВ рдХрд╛ рд╡рд┐рддрд░рдг рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╣реИ:
| рд░реБрдЪрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ | рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ | 
|---|
| 1 | 174,061 | 
| 2 | 279,744 | 
| 3 | 317,212 | 
| 4 | 262,313 | 
| 5 | 128,512 | 
| 6 | 48099 | 
| 7 | 12228 | 
| 8 | 2232 | 
| 9 | 250 | 
| рдЕрд╢рдХреНрдд | 75,349 | 
рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ, рдореИрдВ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рдХреИрд╕реЗ SMALLINT[] рдЬрд╛рд░реА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдорд╛рди рд▓реЗрдВ рдХрд┐ рдкреНрд░рддрд┐ рдЖрдХрд╛рд░ 4 рдмрд╛рдЗрдЯреНрд╕ рдФрд░ 2 рдмрд╛рдЗрдЯреНрд╕ рдкреНрд░рддрд┐ рдорд╛рди рд╣реИрдВред рдлрд┐рд░ 16 рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рдЖрдк 6 рддрддреНрд╡реЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдлрд┐рдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдФрд░ 98% рддрддреНрд╡ 16 рдмрд╛рдЗрдЯреНрд╕ рдФрд░ 16 рдПрдордмреА рдХреЗ рдЕрдВрддрд░ рдореЗрдВ рдлрд┐рдЯ рд╣реЛрдВрдЧреЗред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ bit128 рдкреНрд░рдХрд╛рд░ рдирд┐рд░рд░реНрдердХ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдбреЗрдЯрд╛ рд╕реЗрдЯ рдкрд░ рдорд╛рдирдХ рдкреНрд░рдХрд╛рд░ рдирд┐рд░рд░реНрдердХ рд╣реИред