рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд▓ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬ


рдЕрдВрддрд┐рдо 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_key54 рдПрдордмреА
accounts_phone_key32 рдПрдордмреА
accounts_pkey28 рдПрдордмреА
interests_ids_index8072 рдХреЗрдмреА

рдЕрдВрддрд┐рдо рд╕рд░реНрдХрд┐рдЯ:


 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_key32 рдПрдордмреА28 рдПрдордмреА
accounts_pkey28 рдПрдордмреА28 рдПрдордмреА
interests_ids_index8072 рдХреЗрдмреА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_key28 рдПрдордмреА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: // && if (*nentries > 0) { *searchMode = GIN_SEARCH_MODE_DEFAULT; } else { *searchMode = GIN_SEARCH_MODE_ALL; } break; case RTContainsStrategyNumber: // @> if (*nentries > 0) { *searchMode = GIN_SEARCH_MODE_DEFAULT; } else { *searchMode = GIN_SEARCH_MODE_ALL; } break; } PG_RETURN_POINTER(res); } 

рдкрд╣рд▓рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рдорд╛рди рдСрдкрд░реЗрдЯрд░ рдХреЗ рджрд╛рдИрдВ рдУрд░ рд╕реЗ рдЧреБрдЬрд░рддрд╛ рд╣реИ, рддреАрд╕рд░рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рд░рдгрдиреАрддрд┐ (рдСрдкрд░реЗрдЯрд░) рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬ рдХреА рдЬрд╛рддреА рд╣реИред рдЦреЛрдЬ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рдмреЗрд╣рддрд░ рдкрд░рд┐рдЪрд┐рдд рд╣реИред рдЕрдиреБрдкрд╛рд▓рди рд╕рдорд╛рд░реЛрд╣:


 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: // && { for (int i = 0; i < nkeys; ++i) { if (check[i]) { res = true; } }; *recheck = false; } break; case RTContainsStrategyNumber: // @> { for (int i = 0; i < nkeys; ++i) { if (check[i]) { res = true; } }; *recheck = true; } break; } PG_RETURN_BOOL(res); } 

рдпрджрд┐ рдЕрдиреБрдХреНрд░рдорд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рд░рдгрдиреАрддрд┐ рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдХреНрд╡реЗрд░реА рдСрдкрд░реЗрдЯрд░ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рддрд╛ 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_index8072 рдХреЗрдмреА8072 рдХреЗрдмреА

рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдкрд░рд┐рдгрд╛рдо рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдмрд╛рд░реАрдХрд┐рдпрд╛рдВ рд╣реИрдВ:


  • рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рднреМрддрд┐рдХ рднрдВрдбрд╛рд░рдг;
  • рдбреЗрдЯрд╛ рд╡рд┐рддрд░рдгред

рд╕рднреА рдмрдирд╛рдП рдЧрдП рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЖрдХрд╛рд░ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЙрдирдХреЗ рд▓рд┐рдП PLAIN рд╕рдВрдЧреНрд░рд╣рдг рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдВрдкреАрдбрд╝рди рдФрд░ рдЕрд▓рдЧ рднрдВрдбрд╛рд░рдг рдЙрди рдкрд░ рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЪрд░-рд▓рдВрдмрд╛рдИ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдЕрд░реНрд░реЗ рдФрд░ рддрд╛рд░ рдЯреЛрд╕реНрдЯ рд╕реЗ рд╣реЛрдХрд░ рдЧреБрдЬрд░рддреЗ рд╣реИрдВред рд╣рд╛рдВ, рднрдВрдбрд╛рд░рдг рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдУрд╡рд░рд╣реЗрдб рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрдкреАрдбрд╝рди рднреА рд╣реИред


рд╣рд┐рддреЛрдВ рдХрд╛ рд╡рд┐рддрд░рдг рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╣реИ:


рд░реБрдЪрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ
1174,061
2279,744
3317,212
4262,313
5128,512
648099
712228
82232
9250
рдЕрд╢рдХреНрдд75,349

рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ, рдореИрдВ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рдХреИрд╕реЗ SMALLINT[] рдЬрд╛рд░реА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдорд╛рди рд▓реЗрдВ рдХрд┐ рдкреНрд░рддрд┐ рдЖрдХрд╛рд░ 4 рдмрд╛рдЗрдЯреНрд╕ рдФрд░ 2 рдмрд╛рдЗрдЯреНрд╕ рдкреНрд░рддрд┐ рдорд╛рди рд╣реИрдВред рдлрд┐рд░ 16 рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рдЖрдк 6 рддрддреНрд╡реЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдлрд┐рдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдФрд░ 98% рддрддреНрд╡ 16 рдмрд╛рдЗрдЯреНрд╕ рдФрд░ 16 рдПрдордмреА рдХреЗ рдЕрдВрддрд░ рдореЗрдВ рдлрд┐рдЯ рд╣реЛрдВрдЧреЗред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ bit128 рдкреНрд░рдХрд╛рд░ рдирд┐рд░рд░реНрдердХ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдбреЗрдЯрд╛ рд╕реЗрдЯ рдкрд░ рдорд╛рдирдХ рдкреНрд░рдХрд╛рд░ рдирд┐рд░рд░реНрдердХ рд╣реИред

Source: https://habr.com/ru/post/hi442058/


All Articles