-5

功能代码。它的工作非常缓慢。我怎样才能加快速度

    CREATE OR REPLACE FUNCTION bill."ReportIngredients"(
    _from date,
    _to date,
    _beginning_date date,
    _has_inventory boolean,
    _inventory_id uuid,
    _restaurant_id uuid,
    _stock_id uuid,
    _ingredientIds uuid [],
    _sort_by character varying,
    _limit integer,
    _offset integer

  )
  RETURNS TABLE(
    json json
  ) AS
$BODY$
declare
  ingredientFilter character varying = '';
  ingredient_id uuid;
  ss_date date;
begin
  if ( _ingredientIds is not null ) then
    ingredientFilter = 'and i.id IN (';
    FOREACH ingredient_id in array _ingredientIds loop
      ingredientFilter := ingredientFilter || '''' ||  ingredient_id ||  ''',';
    end loop;
    Select trim(trailing ',' from ingredientFilter) into ingredientFilter;
    ingredientFilter := ingredientFilter || ') ';
  end if;

  if ( _has_inventory ) then
  return query execute
    'select array_to_json(array_agg(row_to_json(t)))
      From (
        Select i.id, i.title,
          (
            (
              SELECT coalesce(sum(ii.delta_count), 0)
              FROM inventory_ingredients ii
              Inner Join inventories inven On inven.id = ii.inventory_id
              WHERE ii.ingredient_id = i.id
                And inven.is_active = true
                And inven.stock_id = ''' || _stock_id || '''
                And inven.id = ''' || _inventory_id || '''
            ) + (
              SELECT coalesce(sum(ii.count), 0)
              FROM invoice_ingredients ii
              Inner Join invoices invo On invo.id = ii.invoice_id
              WHERE ii.is_active = true
                And ii.ingredient_id = i.id
                And invo.is_active = true
                And invo.restaurant_id = ''' || _restaurant_id || '''
                And invo.receiver_id = ''' || _stock_id || '''
                And invo.date >= ''' || _beginning_date || '''
                And invo.date < ''' || _from || '''
            ) + (
              SELECT coalesce(sum(ri.count), 0)
              FROM relocation_ingredients ri
              Inner Join relocations r On r.id = ri.relocation_id
              WHERE ri.ingredient_id = i.id
                And r.is_active = true
                And r.restaurant_id = ''' || _restaurant_id || '''
                And r.receiver_stock_id = ''' || _stock_id || '''
                And r.date >= ''' || _beginning_date || '''
                And r.date < ''' || _from || '''
            ) - (
              SELECT coalesce(sum(wi.count), 0)
              FROM write_off_ingredients wi
              Inner Join write_offs w On w.id = wi.write_off_id
              WHERE wi.ingredient_id = i.id
                And w.is_active = true
                And w.stock_id = ''' || _stock_id || '''
                And w.date >= ''' || _beginning_date || '''
                And w.date < ''' || _from || '''
            ) - (
              SELECT coalesce(sum(ri.count), 0)
              FROM relocation_ingredients ri
              Inner Join relocations r On r.id = ri.relocation_id
              WHERE ri.ingredient_id = i.id
                And r.is_active = true
                And r.restaurant_id = ''' || _restaurant_id || '''
                And r.sender_stock_id = ''' || _stock_id || '''
                And r.date >= ''' || _beginning_date || '''
                And r.date < ''' || _from || '''
            ) - (
                Select ((
                  SELECT coalesce(sum(bc.count), 0)
                  FROM bill_calculations bc
                  Inner Join bill.bill_course_solds bcs on bcs.id = bc.object_id
                  Inner Join bill.bills b on b.id = bcs.bill_id
                  WHERE bc.ingredient_id = i.id
                    And bc.stock_id = ''' || _stock_id || '''
                    And bc.date >= ''' || _beginning_date || '''
                    And bc.date < ''' || _from || '''
                    And bc.calculate_type = ''subtract''
                    And b.bill_type <> 5
                )  - (
                  SELECT coalesce(sum(bc.count), 0)
                  FROM bill_calculations bc
                  Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
                  Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
                  Inner Join bill.bills b on b.id = bcs.bill_id
                  WHERE bc.ingredient_id = i.id
                    And bc.stock_id = ''' || _stock_id || '''
                    And bc.date >= ''' || _beginning_date || '''
                    And bc.date < ''' || _from || '''
                    And bc.calculate_type = ''add''
                    And b.bill_type <> 5
                )) AS sum
            )
          ) AS start_count,
          (
            SELECT coalesce(sum(ii.count), 0)
            FROM invoice_ingredients ii
            Inner Join invoices invo On invo.id = ii.invoice_id
            WHERE ii.is_active = true
              And ii.ingredient_id = i.id
              And invo.is_active = true
              And invo.restaurant_id = ''' || _restaurant_id || '''
              And invo.receiver_id = ''' || _stock_id || '''
              And invo.date >= ''' || _from || '''
              And invo.date <= ''' || _to || '''
          ) AS invoice_count,
          (
            SELECT coalesce(sum(ri.count), 0)
            FROM relocation_ingredients ri
            Inner Join relocations r On r.id = ri.relocation_id
            WHERE ri.ingredient_id = i.id
              And r.is_active = true
              And r.restaurant_id = ''' || _restaurant_id || '''
              And r.receiver_stock_id = ''' || _stock_id || '''
              And r.date >= ''' || _from || '''
              And r.date <= ''' || _to || '''
          ) AS relocation_in_count,

          (
            SELECT coalesce(sum(wi.count), 0)
            FROM write_off_ingredients wi
            Inner Join write_offs w On w.id = wi.write_off_id
            WHERE wi.ingredient_id = i.id
              And w.is_active = true
              And w.stock_id = ''' || _stock_id || '''
              And w.date >= ''' || _from || '''
              And w.date <= ''' || _to || '''
          ) AS write_off_count,
          (
            SELECT coalesce(sum(ri.count), 0)
            FROM relocation_ingredients ri
            Inner Join relocations r On r.id = ri.relocation_id
            WHERE ri.ingredient_id = i.id
              And r.is_active = true
              And r.restaurant_id = ''' || _restaurant_id || '''
              And r.sender_stock_id = ''' || _stock_id || '''
              And r.date >= ''' || _from || '''
              And r.date <= ''' || _to || '''
          ) AS relocation_out_count,
          (
              Select ((
                SELECT coalesce(sum(bc.count), 0)
                FROM bill_calculations bc
                Inner Join bill.bill_course_solds bcs on bcs.id = bc.object_id
                Inner Join bill.bills b on b.id = bcs.bill_id
                WHERE bc.ingredient_id = i.id
                  And bc.stock_id = ''' || _stock_id || '''
                  And bc.date >= ''' || _from || '''
                  And bc.date <= ''' || _to || '''
                  And bc.calculate_type = ''subtract''
                  And b.bill_type <> 5
              )  - (
                SELECT coalesce(sum(bc.count), 0)
                FROM bill_calculations bc
                Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
                Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
                Inner Join bill.bills b on b.id = bcs.bill_id
                WHERE bc.ingredient_id = i.id
                  And bc.stock_id = ''' || _stock_id || '''
                  And bc.date >= ''' || _from || '''
                  And bc.date <= ''' || _to || '''
                  And bc.calculate_type = ''add''
                  And b.bill_type <> 5
              )) AS sum
          ) AS solds_count,
          (
            SELECT coalesce(sum(bc.count), 0)
            FROM bill_calculations bc
            Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
            Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
            Inner Join bill.bills b on b.id = bcs.bill_id
            WHERE bc.ingredient_id = i.id
              And bc.stock_id = ''' || _stock_id || '''
              And bc.date >= ''' || _from || '''
              And bc.date <= ''' || _to || '''
              And bc.calculate_type = ''add''
              And b.bill_type <> 5
          ) AS resign_count
        From ingredients i
        Where i.is_active = true
          And i.restaurant_id = ''' || _restaurant_id || '''
          ' || ingredientFilter || '
        Group by i.id
        order by ' || _sort_by || '
        limit ' || _limit || '
        offset ' || _offset || '
    ) t';
  else
    return query execute
      'select array_to_json(array_agg(row_to_json(t)))
        From (
          Select i.id, i.title,
            (
              (
                SELECT coalesce(sum(ii.count), 0)
                FROM invoice_ingredients ii
                Inner Join invoices invo On invo.id = ii.invoice_id
                WHERE ii.is_active = true
                  And ii.ingredient_id = i.id
                  And invo.is_active = true
                  And invo.restaurant_id = ''' || _restaurant_id || '''
                  And invo.receiver_id = ''' || _stock_id || '''
                  And invo.date >= ''' || _beginning_date || '''
                  And invo.date < ''' || _from || '''
              ) + (
                SELECT coalesce(sum(ri.count), 0)
                FROM relocation_ingredients ri
                Inner Join relocations r On r.id = ri.relocation_id
                WHERE ri.ingredient_id = i.id
                  And r.is_active = true
                  And r.restaurant_id = ''' || _restaurant_id || '''
                  And r.receiver_stock_id = ''' || _stock_id || '''
                  And r.date >= ''' || _beginning_date || '''
                  And r.date < ''' || _from || '''
              ) - (
                SELECT coalesce(sum(wi.count), 0)
                FROM write_off_ingredients wi
                Inner Join write_offs w On w.id = wi.write_off_id
                WHERE wi.ingredient_id = i.id
                  And w.is_active = true
                  And w.stock_id = ''' || _stock_id || '''
                  And w.date >= ''' || _beginning_date || '''
                  And w.date < ''' || _from || '''
              ) - (
                SELECT coalesce(sum(ri.count), 0)
                FROM relocation_ingredients ri
                Inner Join relocations r On r.id = ri.relocation_id
                WHERE ri.ingredient_id = i.id
                  And r.is_active = true
                  And r.restaurant_id = ''' || _restaurant_id || '''
                  And r.sender_stock_id = ''' || _stock_id || '''
                  And r.date >= ''' || _beginning_date || '''
                  And r.date < ''' || _from || '''
              ) - (
                  Select ((
                    SELECT coalesce(sum(bc.count), 0)
                    FROM bill_calculations bc
                    Inner Join bill.bill_course_solds bcs on bcs.id = bc.object_id
                    Inner Join bill.bills b on b.id = bcs.bill_id
                    WHERE bc.ingredient_id = i.id
                      And bc.stock_id = ''' || _stock_id || '''
                      And bc.date >= ''' || _beginning_date || '''
                      And bc.date < ''' || _from || '''
                      And bc.calculate_type = ''subtract''
                      And b.bill_type <> 5
                  )  - (
                    SELECT coalesce(sum(bc.count), 0)
                    FROM bill_calculations bc
                    Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
                    Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
                    Inner Join bill.bills b on b.id = bcs.bill_id
                    WHERE bc.ingredient_id = i.id
                      And bc.stock_id = ''' || _stock_id || '''
                      And bc.date >= ''' || _beginning_date || '''
                      And bc.date < ''' || _from || '''
                      And bc.calculate_type = ''add''
                      And b.bill_type <> 5
                  )) AS sum
              )
            ) AS start_count,
            (
              SELECT coalesce(sum(ii.count), 0)
              FROM invoice_ingredients ii
              Inner Join invoices invo On invo.id = ii.invoice_id
              WHERE ii.is_active = true
                And ii.ingredient_id = i.id
                And invo.is_active = true
                And invo.restaurant_id = ''' || _restaurant_id || '''
                And invo.receiver_id = ''' || _stock_id || '''
                And invo.date >= ''' || _from || '''
                And invo.date <= ''' || _to || '''
            ) AS invoice_count,
            (
              SELECT coalesce(sum(ri.count), 0)
              FROM relocation_ingredients ri
              Inner Join relocations r On r.id = ri.relocation_id
              WHERE ri.ingredient_id = i.id
                And r.is_active = true
                And r.restaurant_id = ''' || _restaurant_id || '''
                And r.receiver_stock_id = ''' || _stock_id || '''
                And r.date >= ''' || _from || '''
                And r.date <= ''' || _to || '''
            ) AS relocation_in_count,
            (
              SELECT coalesce(sum(wi.count), 0)
              FROM write_off_ingredients wi
              Inner Join write_offs w On w.id = wi.write_off_id
              WHERE wi.ingredient_id = i.id
                And w.is_active = true
                And w.stock_id = ''' || _stock_id || '''
                And w.date >= ''' || _from || '''
                And w.date <= ''' || _to || '''
            ) AS write_off_count,
            (
              SELECT coalesce(sum(ri.count), 0)
              FROM relocation_ingredients ri
              Inner Join relocations r On r.id = ri.relocation_id
              WHERE ri.ingredient_id = i.id
                And r.is_active = true
                And r.restaurant_id = ''' || _restaurant_id || '''
                And r.sender_stock_id = ''' || _stock_id || '''
                And r.date >= ''' || _from || '''
                And r.date <= ''' || _to || '''
            ) AS relocation_out_count,
            (
                Select ((
                  SELECT coalesce(sum(bc.count), 0)
                  FROM bill_calculations bc
                  Inner Join bill.bill_course_solds bcs on bcs.id = bc.object_id
                  Inner Join bill.bills b on b.id = bcs.bill_id
                  WHERE bc.ingredient_id = i.id
                    And bc.stock_id = ''' || _stock_id || '''
                    And bc.date >= ''' || _from || '''
                    And bc.date <= ''' || _to || '''
                    And bc.calculate_type = ''subtract''
                    And b.bill_type <> 5
                )  - (
                  SELECT coalesce(sum(bc.count), 0)
                  FROM bill_calculations bc
                  Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
                  Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
                  Inner Join bill.bills b on b.id = bcs.bill_id
                  WHERE bc.ingredient_id = i.id
                    And bc.stock_id = ''' || _stock_id || '''
                    And bc.date >= ''' || _from || '''
                    And bc.date <= ''' || _to || '''
                    And bc.calculate_type = ''add''
                    And b.bill_type <> 5
                )) AS sum
            ) AS solds_count,
            (
              SELECT coalesce(sum(bc.count), 0)
              FROM bill_calculations bc
              Inner Join bill.bill_course_resigns bcr on bcr.id = bc.object_id
              Inner Join bill.bill_course_solds bcs on bcs.id = bcr.bill_course_sold_id
              Inner Join bill.bills b on b.id = bcs.bill_id
              WHERE bc.ingredient_id = i.id
                And bc.stock_id = ''' || _stock_id || '''
                And bc.date >= ''' || _from || '''
                And bc.date <= ''' || _to || '''
                And bc.calculate_type = ''add''
                And b.bill_type <> 5
            ) AS resign_count
          From ingredients i
          Where i.is_active = true
            And i.restaurant_id = ''' || _restaurant_id || '''
            ' || ingredientFilter || '
          Group by i.id
          order by ' || _sort_by || '
          limit ' || _limit || '
          offset ' || _offset || '
      ) t';
    end if;
end;

$BODY$
  LANGUAGE plpgsql STABLE
  COST 50
  ROWS 1000;
ALTER FUNCTION bill."ReportIngredients"(date, date, date, boolean, uuid, uuid, uuid, uuid[], character varying, integer, integer)
  OWNER TO developer;

解释分析结果

“结果(成本=0.00..5.13 行=1000 宽度=0)(实际时间=38859.253..38859.254 行=1 循环=1)”
“总运行时间:38859.296 毫秒”
4

1 回答 1

2

那里有大约 14 个子查询,由于缺少索引或错误的统计信息,其中任何一个都可能导致 90% 的执行时间,而且每个子查询似乎都针对成分表查询中投射的每种成分执行。因此,如果有 50 个成分,那么子查询的每次执行平均可能需要 40 毫秒——这听起来不合理吗?

我建议您执行实际的 SQL,并查看子查询是否确实执行了很多次。如果是这样,请尝试将查询重组为一组公用表表达式,从成分的选择开始,每个子查询使用一个 CTE,您可以在其中加入成分列表并聚合到成分级别。在查询的最后部分将 CTE 连接在一起。

你最终会是这样的:

with
  cte_ingredients as (
    select id,
           title
    from   ingredients
    where  ...),
  cte_invoice_ingredients as (
    SELECT i.id,
           sum(ii.count) amt
    FROM cte_ingredients i join
         invoice_ingredients ii on ii.ingredient_id = i.id
          Inner Join invoices invo On invo.id = ii.invoice_id
   WHERE ii.is_active = true
         And invo.is_active = true
         And invo.restaurant_id = ''' || _restaurant_id || '''
         And invo.receiver_id = ''' || _stock_id || '''
         And invo.date >= ''' || _beginning_date || '''
         And invo.date < ''' || _from || '''
   group by i.id),
   ... rest of the CTE's ...
select i.id,
       i.title,
       coalesce(ii.amt,0) ii_amt,
       ... blah blah arithmetic ..
from cte_ingredients i left join
     cte_invoice_ingredients ii on i.id = ii.id
于 2013-07-09T22:38:11.840 回答