Простой, но медленный SQL-запрос с PostgreSQL

/*$mpdf = new mPDF('',    // mode - default ''
 '',    // format - A4, for example, default ''
 0,     // font size - default 0
 '',    // default font family
 15,    // margin_left
 15,    // margin right
 16,     // margin top
 16,    // margin bottom
 9,     // margin header
 9,     // margin footer
 'L');  // L - landscape, P - portrait*/
1
задан Mike Sherrill 'Cat Recall' 27 February 2019 в 15:17
поделиться

2 ответа

Ваш запрос собирает много данных, поэтому можно ожидать, что он будет медленным.

Последовательное сканирование на order является самым быстрым методом, потому что вам нужна половина строк в таблице.

В целом, PostgreSQL должен прочитать более миллиона блоков, чтобы вычислить результат и обработать все эти данные, поэтому три минуты неплохие.

Я сомневаюсь, что этот запрос можно сделать быстрее.

0
ответ дан Laurenz Albe 27 February 2019 в 15:17
поделиться
  • time - недопустимое имя для столбца (отметка времени!), Избегайте его
  • order - недопустимое имя для таблицы, избегайте его
  • индекс, отсутствующий для `close_time '
  • , старается избегать значений NULL в столбцах меток времени ( почти поле ключа), избегая вместо этого` ... OR xxx IS NULL
  • вы можете использовать разумные значения по умолчанию, такие как now() или +/-infinity
  • , последний шаг сортировки может разрушить ваш план yuery.

Также: вам, вероятно, не нужен суррогатный ключ id на order_history. Достаточно натурального ключа (order_id,ztime).


\i tmp.sql

CREATE TABLE orders (
    id uuid NOT NULL
    , side varchar(4) NOT NULL
    , product varchar(7) NOT NULL
    , price numeric(18,8) NOT NULL
    , close_time timestamp NOT  NULL DEFAULT ('infinity'::timestamp)
    , CONSTRAINT order_pkey PRIMARY KEY (id)
);
CREATE TABLE order_history (
    id serial NOT NULL
    , amount numeric(18,8) NOT NULL
    , ztime timestamp NOT NULL  DEFAULT ('-infinity'::timestamp)
    , order_id uuid NOT NULL
    , CONSTRAINT order_history_pkey PRIMARY KEY (id)
    , CONSTRAINT order_history_order_id_fkey FOREIGN KEY (order_id) REFERENCES orders(id)
);

-- CREATE INDEX order_history_order_id ON order_history USING btree (order_id);
-- CREATE INDEX order_history_time_idx ON order_history USING btree (ztime);
CREATE INDEX order_history_order_id_ztime ON order_history USING btree (order_id,ztime);
CREATE INDEX order_h_ztime ON orders USING btree (close_time);

EXPLAIN
select
    oo.id
    , oo.side
    , oo.price
    , oo.close_time
    , oh.ztime
    , oh.amount
from
    orders as oo
inner join order_history as oh on oh.order_id = oo.id
where oh.ztime <= '2018-03-28 08:00:00'
    and (oo.close_time > '2018-03-28 07:00:00' ) -- or oo.close_time is null)
    and oo.product = 'BTC-USD'
order by oh.ztime
        ;

Результирующий план (без каких-либо данных !!!):


                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=16.98..16.99 rows=1 width=92)
   Sort Key: oh.ztime
   ->  Nested Loop  (cost=3.14..16.98 rows=1 width=92)
         ->  Bitmap Heap Scan on orders oo  (cost=1.94..13.64 rows=1 width=64)
               Recheck Cond: (close_time > '2018-03-28 07:00:00'::timestamp without time zone)
               Filter: ((product)::text = 'BTC-USD'::text)
               ->  Bitmap Index Scan on order_h_ztime  (cost=0.00..1.94 rows=213 width=0)
                     Index Cond: (close_time > '2018-03-28 07:00:00'::timestamp without time zone)
         ->  Bitmap Heap Scan on order_history oh  (cost=1.20..3.33 rows=2 width=44)
               Recheck Cond: ((order_id = oo.id) AND (ztime <= '2018-03-28 08:00:00'::timestamp without time zone))
               ->  Bitmap Index Scan on order_history_order_id_ztime  (cost=0.00..1.20 rows=2 width=0)
                     Index Cond: ((order_id = oo.id) AND (ztime <= '2018-03-28 08:00:00'::timestamp without time zone))
(12 rows)
0
ответ дан wildplasser 27 February 2019 в 15:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: