postgres函数重复执行5-6次后失败

问题描述 投票:0回答:1
SELECT * 
FROM public.admin_get_sales_data(1, 5000,
                                 null, null, null, null,
                                 null, null, null)

使用不同的第一个参数 1,2,3... 调用此函数,它会在任何随机执行 5 或 6 次时失败。这个问题的原因和解决办法是什么?

第五次尝试长时间执行查询后出现错误消息。
用户查询可能需要查看必须删除的行版本。由于与恢复冲突而取消语句

这是函数体:

CREATE OR REPLACE FUNCTION public.admin_get_sales_data(
    page_num integer,
    page_size integer,
    filter_market_id integer,
    filter_partner_id integer,
    filter_order_rating integer[],
    filter_display_id_pattern text,
    filter_date_range text,
    start_date timestamp with time zone,
    end_date timestamp with time zone)
    RETURNS TABLE(id integer, display_id character, customer_name text, partner_name character varying, partner_id integer, total_amount numeric, created_at timestamp with time zone, updated_at timestamp with time zone, items text, market_id integer, market_name character varying, order_status character varying, order_rating smallint, review text, bag_created_times timestamp without time zone[], surplus_discount_percentage numeric, deal_discount_percentage numeric, timezone_name character varying) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
    ROWS 1000

AS $BODY$
BEGIN
    RETURN QUERY
    WITH bag_counts AS (
        SELECT
            bl.partner_id,
            bl.order_id,
            bl.bag_type,
            bl.bag_price,
            bl.retail_price,
            COUNT(*) AS bag_count
        FROM
            bags_listing bl
        GROUP BY
            bl.partner_id,
            bl.order_id,
            bl.bag_type,
            bl.bag_price,
            bl.retail_price
    ),
    cancelled_bag_counts AS (
        SELECT
            bl.partner_id,
            clbl.order_id,
            bl.bag_type,
            bl.bag_price,
            bl.retail_price,
            COUNT(*) AS bag_count
        FROM
            bags_listing bl
        JOIN cancelled_order_bags_listing_map clbl ON bl.id = clbl.bag_listing_id
        GROUP BY
            bl.partner_id,
            clbl.order_id,
            bl.bag_type,
            bl.bag_price,
            bl.retail_price
    )
    SELECT
        od.id,
        od.display_id,
        CONCAT(cust.first_name, ' ', cust.last_name) AS customer_name,
        pt.shop_name AS partner_name,
        pt.id AS partner_id,
        od.total_amount AS total_amount,
        od.created_at,
        od.updated_at,
        CASE
            WHEN od.order_status = 'CANCELLED' THEN (
                CASE
                    WHEN COALESCE(cbc_big.bag_count, 0) > 0 THEN CONCAT(COALESCE(cbc_big.bag_count, 0), 'x Big bag')
                    ELSE ''
                END || 
                CASE
                    WHEN COALESCE(cbc_small.bag_count, 0) > 0 THEN CONCAT(CASE WHEN COALESCE(cbc_big.bag_count, 0) > 0 THEN ', ' ELSE '' END, COALESCE(cbc_small.bag_count, 0), 'x Small bag')
                    ELSE '' 
                END || 
                CASE
                     WHEN COALESCE(cbc_deal.bag_count, 0) > 0 THEN CONCAT(CASE WHEN COALESCE(cbc_big.bag_count, 0) > 0 OR COALESCE(cbc_small.bag_count, 0) > 0 THEN ', ' ELSE '' END, COALESCE(cbc_deal.bag_count, 0), 'x Deal bag')
                     WHEN cbc_big.bag_count IS NOT NULL THEN ''
                     WHEN cbc_small.bag_count IS NOT NULL THEN ''
                     ELSE 'NA'
                END
            )
            ELSE (
                CASE
                    WHEN COALESCE(bc_big.bag_count, 0) > 0 THEN CONCAT(COALESCE(bc_big.bag_count, 0), 'x Big bag')
                    ELSE ''
                END || 
                CASE
                    WHEN COALESCE(bc_small.bag_count, 0) > 0 THEN CONCAT(CASE WHEN COALESCE(bc_big.bag_count, 0) > 0 THEN ', ' ELSE '' END, COALESCE(bc_small.bag_count, 0), 'x Small bag')
                    ELSE '' 
                END || 
                CASE
                     WHEN COALESCE(bc_deal.bag_count, 0) > 0 THEN CONCAT(CASE WHEN COALESCE(bc_big.bag_count, 0) > 0 OR COALESCE(bc_small.bag_count, 0) > 0 THEN ', ' ELSE '' END, COALESCE(bc_deal.bag_count, 0), 'x Deal bag')
                     WHEN bc_big.bag_count IS NOT NULL THEN ''
                     WHEN bc_small.bag_count IS NOT NULL THEN ''
                     ELSE 'NA'
                END
            )
        END AS items,
        pt.market_id AS market_id,
        mt.market_name,
        od.order_status,
        pr.rating AS order_rating,
        pr.comment AS review, 
        CASE
            WHEN od.order_status = 'CANCELLED' THEN (
                SELECT ARRAY(
                    SELECT 
                        CASE 
                            WHEN pt.utc_minutes_offset IS NOT NULL 
                            THEN bl.created_at AT TIME ZONE 'UTC' + INTERVAL '1 minute' * pt.utc_minutes_offset 
                            ELSE bl.created_at::timestamp without time zone
                        END
                    FROM bags_listing bl
                    JOIN cancelled_order_bags_listing_map clbl ON bl.id = clbl.bag_listing_id
                    WHERE clbl.order_id = od.id
                    ORDER BY bl.created_at
                )
            )
            ELSE (
                SELECT ARRAY(
                    SELECT 
                        CASE 
                            WHEN pt.utc_minutes_offset IS NOT NULL 
                            THEN bl.created_at AT TIME ZONE 'UTC' + INTERVAL '1 minute' * pt.utc_minutes_offset 
                            ELSE bl.created_at::timestamp without time zone
                        END
                    FROM bags_listing bl
                    WHERE bl.order_id = od.id
                    ORDER BY bl.created_at
                )
            )
        END AS bag_created_times,
        CASE  
            WHEN COALESCE(bc_big.bag_count, 0) > 0 
              OR COALESCE(cbc_big.bag_count, 0) > 0 
              OR COALESCE(bc_small.bag_count, 0) > 0 
              OR COALESCE(cbc_small.bag_count, 0) > 0 
            THEN 66.67 
            ELSE 0.00 
        END AS surplus_discount_percentage,
        CASE
            WHEN COALESCE(bc_deal.bag_count, 0) > 0 OR COALESCE(cbc_deal.bag_count, 0) > 0 THEN
                ROUND(
                    (
                        GREATEST(COALESCE(bc_deal.retail_price, 0), COALESCE(cbc_deal.retail_price, 0)) - 
                        GREATEST(COALESCE(bc_deal.bag_price, 0), COALESCE(cbc_deal.bag_price, 0))
                    ) / 
                    GREATEST(COALESCE(bc_deal.retail_price, 0), COALESCE(cbc_deal.retail_price, 0)) * 100,
                    2
                )
            ELSE
                0.00
        END AS deal_discount_percentage,
        pt.timezone_name 
    FROM
        public.orders od
    JOIN 
        public.customers cust ON od.customer_id = cust.id
    JOIN 
        public.partners pt ON od.partner_id = pt.id
    LEFT JOIN bag_counts bc_big ON od.partner_id = bc_big.partner_id AND od.id = bc_big.order_id AND bc_big.bag_type = 1
    LEFT JOIN bag_counts bc_small ON od.partner_id = bc_small.partner_id AND od.id = bc_small.order_id AND bc_small.bag_type = 2
    LEFT JOIN bag_counts bc_deal ON od.partner_id = bc_deal.partner_id AND od.id = bc_deal.order_id AND bc_deal.bag_type = 3
    LEFT JOIN cancelled_bag_counts cbc_big ON od.partner_id = cbc_big.partner_id AND od.id = cbc_big.order_id AND cbc_big.bag_type = 1
    LEFT JOIN cancelled_bag_counts cbc_small ON od.partner_id = cbc_small.partner_id AND od.id = cbc_small.order_id AND cbc_small.bag_type = 2
    LEFT JOIN cancelled_bag_counts cbc_deal ON od.partner_id = cbc_deal.partner_id AND od.id = cbc_deal.order_id AND cbc_deal.bag_type = 3
    JOIN 
        markets mt ON pt.market_id = mt.id
    LEFT JOIN (
        SELECT
            order_id,
            rating,
            comment
        FROM
            partner_ratings
        GROUP BY
            order_id,
            rating,
            comment
    ) pr ON od.id = pr.order_id
    WHERE
        od.order_status IN ('COMPLETED', 'CONFIRMED', 'CANCELLED', 'REFUNDED')
        AND (filter_market_id IS NULL OR pt.market_id = filter_market_id)
        AND (filter_partner_id IS NULL OR pt.id = filter_partner_id)
        AND (filter_display_id_pattern IS NULL OR od.display_id ILIKE '%' || filter_display_id_pattern || '%') -- Apply the display_id filter
        AND (
            CASE
                WHEN filter_date_range = 'All Time' THEN true
                WHEN filter_date_range = 'This Month' THEN DATE_TRUNC('month', od.created_at) = DATE_TRUNC('month', CURRENT_TIMESTAMP)
                WHEN filter_date_range = 'Today' THEN od.created_at::date = CURRENT_DATE
                WHEN filter_date_range = 'Custom' THEN od.created_at BETWEEN start_date AND end_date
                ELSE true
            END
        )
        -- Apply the filter_order_rating
        AND (filter_order_rating IS NULL OR pr.rating = ANY(filter_order_rating))
    ORDER BY
        od.created_at DESC
    LIMIT
        page_size
    OFFSET
        (page_num - 1) * page_size;
END;
$BODY$;

我们需要在此功能中解决这个问题

postgresql
1个回答
0
投票

您可以通过增加 max_standby_streaming_delay 为查询提供更长的宽限期。 这样做会带来一些后果,您可能认为可以接受,也可能不认为可以接受。您还可以查看 hot_standby_feedback。

如果没有充分的理由说明为什么查询首先应该很慢,那么您可以尝试使其更快,这样就不会与这些延迟发生冲突。将查询从函数中取出并使用

EXPLAIN (ANALYZE, BUFFERS)
执行它,看看为什么它很慢。 如果它可以预见地在执行一定次数后发生,那么也许 plan_cache_mode = force_custom_plan 会有所帮助,但你也说是随机的,所以谁知道呢。

最后,您可以只在主服务器上查询,而不是在副本服务器上。

© www.soinside.com 2019 - 2024. All rights reserved.