Индексирование таблиц в PostgreSQL - PullRequest
0 голосов
/ 11 ноября 2018

Я хочу проиндексировать свои таблицы для следующего запроса:

select 
    t.*
from main_transaction t 
left join main_profile profile on profile.id = t.profile_id
left join main_customer customer on (customer.id = profile.user_id) 
where
(upper(t.request_no) like upper(('%'||@requestNumber||'%')) or OR upper(c.phone) LIKE upper(concat('%',||@phoneNumber||,'%')))
 and t.service_type = 'SERVICE_1'
 and t.status  = 'SUCCESS'
 and t.mode = 'AUTO'
 and t.transaction_type = 'WITHDRAW'
 and customer.client = 'corp'
 and t.pub_date>='2018-09-05' and t.pub_date<='2018-11-05'
order by t.pub_date desc, t.id asc 
LIMIT 1000;

Вот как я пытался проиндексировать свои таблицы:

CREATE INDEX main_transaction_pr_id ON main_transaction (profile_id);
CREATE INDEX main_profile_user_id ON main_profile (user_id);
CREATE INDEX main_customer_client ON main_customer (client);
CREATE INDEX main_transaction_gin_req_no ON main_transaction USING gin (upper(request_no) gin_trgm_ops);
CREATE INDEX main_customer_gin_phone ON main_customer USING gin (upper(phone) gin_trgm_ops);
CREATE INDEX main_transaction_general ON main_transaction (service_type, status, mode, transaction_type); --> don't know if this one is true!!

После индексации, как указано выше, мой запрос тратит более 4,5 секунд на выбор 1000 строк!

Я выбираю из следующей таблицы, в которой 34 столбца, включая 3 КЛЮЧА ИНОСТРАННЫХ, и более 3 миллионов строк данных:

CREATE TABLE main_transaction (
   id integer NOT NULL DEFAULT nextval('main_transaction_id_seq'::regclass),
   description character varying(255) NOT NULL,
   request_no character varying(18),
   account character varying(50),
   service_type character varying(50),
   pub_date" timestamptz(6) NOT NULL,
   "service_id" varchar(50) COLLATE "pg_catalog"."default",
   ....
 );

Я также соединяю две таблицы (main_profile, main_customer) для поиска customer.phone и для выбора customer.client. Чтобы добраться до таблицы main_customer из таблицы main_transaction, я могу пойти только на main_profile

У меня вопрос: как я могу проиндексировать мою таблицу, чтобы повысить производительность для вышеуказанного запроса?

Пожалуйста, не используйте UNION для OR для этого случая (upper(t.request_no) like upper(('%'||@requestNumber||'%')) or OR upper(c.phone) LIKE upper(concat('%',||@phoneNumber||,'%'))) Вместо этого мы можем использовать условие case when? Потому что я должен преобразовать свой запрос PostgreSQL в JPA Hibernate! И я не знаю, как конвертировать UNION, кроме Hibernate - Native SQL, который мне запрещено использовать.

Объясните:

Limit  (cost=411601.73..411601.82 rows=38 width=1906) (actual time=3885.380..3885.381 rows=1 loops=1)
  ->  Sort  (cost=411601.73..411601.82 rows=38 width=1906) (actual time=3885.380..3885.380 rows=1 loops=1)
        Sort Key: t.pub_date DESC, t.id
        Sort Method: quicksort  Memory: 27kB
        ->  Hash Join  (cost=20817.10..411600.73 rows=38 width=1906) (actual time=3214.473..3885.369 rows=1 loops=1)
              Hash Cond: (t.profile_id = profile.id)
              Join Filter: ((upper((t.request_no)::text) ~~ '%20181104-2158-2723948%'::text) OR (upper((customer.phone)::text) ~~ '%20181104-2158-2723948%'::text))
              Rows Removed by Join Filter: 593118
              ->  Seq Scan on main_transaction t  (cost=0.00..288212.28 rows=205572 width=1906) (actual time=0.068..1527.677 rows=593119 loops=1)
                    Filter: ((pub_date >= '2016-09-05 00:00:00+05'::timestamp with time zone) AND (pub_date <= '2018-11-05 00:00:00+05'::timestamp with time zone) AND ((service_type)::text = 'SERVICE_1'::text) AND ((status)::text = 'SUCCESS'::text) AND ((mode)::text = 'AUTO'::text) AND ((transaction_type)::text = 'WITHDRAW'::text))
                    Rows Removed by Filter: 2132732
              ->  Hash  (cost=17670.80..17670.80 rows=180984 width=16) (actual time=211.211..211.211 rows=181516 loops=1)
                    Buckets: 131072  Batches: 4  Memory Usage: 3166kB
                    ->  Hash Join  (cost=6936.09..17670.80 rows=180984 width=16) (actual time=46.846..183.689 rows=181516 loops=1)
                          Hash Cond: (customer.id = profile.user_id)
                          ->  Seq Scan on main_customer customer  (cost=0.00..5699.73 rows=181106 width=16) (actual time=0.013..40.866 rows=181618 loops=1)
                                Filter: ((client)::text = 'corp'::text)
                                Rows Removed by Filter: 16920
                          ->  Hash  (cost=3680.04..3680.04 rows=198404 width=8) (actual time=46.087..46.087 rows=198404 loops=1)
                                Buckets: 131072  Batches: 4  Memory Usage: 2966kB
                                ->  Seq Scan on main_profile profile  (cost=0.00..3680.04 rows=198404 width=8) (actual time=0.008..20.099 rows=198404 loops=1)
Planning time: 0.757 ms
Execution time: 3885.680 ms

1 Ответ

0 голосов
/ 12 ноября 2018

Если вы не используете UNION, вы не получите хороший план.

Вы можете немного ускорить обработку со следующими индексами:

main_transaction ((service_type::text), (status::text), (mode::text),
                  (transaction_type::text), pub_date)
main_customer ((client::text))

Это должно по крайней мере избавить от последовательных проверок, но хеш-соединение, которое занимает львиную долю времени обработки, останется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...