Медленная функция PostgreSQL - PullRequest
       4

Медленная функция PostgreSQL

2 голосов
/ 07 сентября 2010

Я использую этот запрос, чтобы выбрать продукты из моей базы данных.Выполнение этого запроса занимает ~ 0,220 мс.Если я уберу 3 строки, в которых используется функция number_percentage (), все будет быстро (~ 0,07 мс или меньше).

SELECT
 DISTINCT ON (p.id) p.id AS product_id,
 pv.price,
 number_percentage(pv.price,t.percentage) AS price_vat,
 number_percentage(pv.price,pd.size) AS price_discount,
 number_percentage(number_percentage(pv.price,t.percentage),pd.size) AS price_discount_vat

FROM
 product_variant AS pv
INNER JOIN
 product AS p ON p.id=pv.product_id
LEFT JOIN
 product_discount AS pd ON pd.id=pv.product_discount_id
LEFT JOIN
 tax AS t ON t.id=pv.tax_id

ORDER BY
 p.id ASC,
 price_discount ASC

LIMIT 15;

Это функция number_percentage ():

CREATE OR REPLACE FUNCTION number_percentage(n real, p int) RETURNS real AS $$
BEGIN
 IF p IS NULL OR p = 0 THEN
  RETURN n;
 END IF;
 RETURN n * (1 + p / 100);
END;
$$ LANGUAGE plpgsql STABLE;

ОБЪЯСНИТЬ АНАЛИЗ (с ORDER BY Price_discount):

Limit  (cost=4371.05..4372.85 rows=15 width=16) (actual time=308.732..308.911 rows=15 loops=1)
  ->  Unique  (cost=4371.05..4389.59 rows=154 width=16) (actual time=308.724..308.843 rows=15 loops=1)
        ->  Sort  (cost=4371.05..4380.32 rows=3709 width=16) (actual time=308.715..308.757 rows=20 loops=1)
              Sort Key: p.id, (number_percentage(pv.price, pd.size))
              Sort Method:  quicksort  Memory: 467kB
              ->  Hash Left Join  (cost=98.12..4151.16 rows=3709 width=16) (actual time=7.473..287.571 rows=4817 loops=1)
                    Hash Cond: (pv.product_discount_id = pd.id)
                    ->  Hash Left Join  (cost=83.62..288.57 rows=3709 width=16) (actual time=7.363..69.976 rows=4817 loops=1)
                          Hash Cond: (pv.tax_id = t.id)
                          ->  Hash Join  (cost=25.47..174.79 rows=3709 width=16) (actual time=7.333..47.134 rows=4817 loops=1)
                                Hash Cond: (pv.product_id = p.id)
                                ->  Seq Scan on product_variant pv  (cost=0.00..94.17 rows=4817 width=16) (actual time=0.019..10.970 rows=4817 loops=1)
                                ->  Hash  (cost=23.54..23.54 rows=154 width=4) (actual time=7.288..7.288 rows=1501 loops=1)
                                      ->  Seq Scan on product p  (cost=0.00..23.54 rows=154 width=4) (actual time=0.013..3.591 rows=1501 loops=1)
                          ->  Hash  (cost=31.40..31.40 rows=2140 width=8) (actual time=0.013..0.013 rows=1 loops=1)
                                ->  Seq Scan on tax t  (cost=0.00..31.40 rows=2140 width=8) (actual time=0.005..0.006 rows=1 loops=1)
                    ->  Hash  (cost=12.00..12.00 rows=200 width=8) (actual time=0.006..0.006 rows=0 loops=1)
                          ->  Seq Scan on product_discount pd  (cost=0.00..12.00 rows=200 width=8) (actual time=0.002..0.002 rows=0 loops=1)
Total runtime: 309.404 ms

ОБЪЯСНИТЬ АНАЛИЗ (без ORDER BY price_discount):

Limit  (cost=4371.05..4372.85 rows=15 width=16) (actual time=285.012..285.187 rows=15 loops=1)
  ->  Unique  (cost=4371.05..4389.59 rows=154 width=16) (actual time=285.004..285.122 rows=15 loops=1)
        ->  Sort  (cost=4371.05..4380.32 rows=3709 width=16) (actual time=284.995..285.036 rows=20 loops=1)
              Sort Key: p.id
              Sort Method:  quicksort  Memory: 467kB
              ->  Hash Left Join  (cost=98.12..4151.16 rows=3709 width=16) (actual time=6.553..270.930 rows=4817 loops=1)
                    Hash Cond: (pv.product_discount_id = pd.id)
                    ->  Hash Left Join  (cost=83.62..288.57 rows=3709 width=16) (actual time=5.720..64.176 rows=4817 loops=1)
                          Hash Cond: (pv.tax_id = t.id)
                          ->  Hash Join  (cost=25.47..174.79 rows=3709 width=16) (actual time=5.693..42.642 rows=4817 loops=1)
                                Hash Cond: (pv.product_id = p.id)
                                ->  Seq Scan on product_variant pv  (cost=0.00..94.17 rows=4817 width=16) (actual time=0.019..10.173 rows=4817 loops=1)
                                ->  Hash  (cost=23.54..23.54 rows=154 width=4) (actual time=5.651..5.651 rows=1501 loops=1)
                                      ->  Seq Scan on product p  (cost=0.00..23.54 rows=154 width=4) (actual time=0.013..2.810 rows=1501 loops=1)
                          ->  Hash  (cost=31.40..31.40 rows=2140 width=8) (actual time=0.012..0.012 rows=1 loops=1)
                                ->  Seq Scan on tax t  (cost=0.00..31.40 rows=2140 width=8) (actual time=0.005..0.005 rows=1 loops=1)
                    ->  Hash  (cost=12.00..12.00 rows=200 width=8) (actual time=0.006..0.006 rows=0 loops=1)
                          ->  Seq Scan on product_discount pd  (cost=0.00..12.00 rows=200 width=8) (actual time=0.001..0.001 rows=0 loops=1)
Total runtime: 285.719 ms

Почему это так медленно?Функция проста, поэтому я не понимаю этого поведения.

Ответы [ 3 ]

1 голос
/ 07 сентября 2010

Измените функцию со СТАБИЛЬНОЙ на НЕЗАВИСИМОЙ. Мои тесты на 8.4.4 опустили объяснение примерно с 0,14 мс до 0,04 мс за звонок. Поскольку он никогда не попадает в базу данных и действительно является истинной функцией (т. Е. Для каждого входного значения x существует только один и только один возможный f (x)), он действительно должен быть IMMUTABLE. Это должно позволить планировщику оценить его только один раз для каждой пары (n, p) .

Также в вашем коде есть ошибка. Эта строка:

RETURN n * (1 + p / 100);

должно быть так:

RETURN n * (1 + p / 100.0);

Как написано, поскольку p является целым числом, p / 100 будет оцениваться как целочисленное деление, давая неверный результат (по крайней мере из моего предположения о том, что предполагается, что эта функция предполагается делать).

0 голосов
/ 07 сентября 2010

Если вы выполните запрос объяснения в pg admin 3, вы сможете увидеть, как запрос разбивается. Тогда вы можете

иногда добавление индекса решит вашу проблему, в противном случае попробуйте переписать запрос. Вы можете попробовать использовать CTE, но, поскольку ваша функция кажется проблемой , чтение может помочь .

0 голосов
/ 07 сентября 2010

Дикая догадка: проблема ORDER BY price_discount. База данных должна обработать все записи , прежде чем она сможет выполнить какую-либо операцию сортировки и выдать запрошенные 15 результатов.

Не могли бы вы показать нам результаты EXPLAIN ANALYZE с и без ORDER BY?

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