Happy Party o ilang linya ng mga alaala tungkol sa pagkilala sa partitioning sa PostgreSQL10

Preface o kung paano nabuo ang ideya ng sectioning

Dito magsisimula ang kwento: Naaalala mo ba kung paano nagsimula ang lahat. Ang lahat ay sa unang pagkakataon at muli. Matapos ang halos lahat ng mga mapagkukunan para sa pag-optimize ng query ay maubos sa oras na iyon, ang tanong ay lumitaw - ano ang susunod? Ito ay kung paano lumitaw ang ideya ng partitioning.

Happy Party o ilang linya ng mga alaala tungkol sa pagkilala sa partitioning sa PostgreSQL10

Lyrical digression:
Tiyak na 'sa sandaling iyon', dahil bilang ito ay naging out, may mga hindi pa nagamit na optimization reserves. Salamat sa iyo asmm at Habru!

Kaya, paano mo pa mapapaligaya ang customer, at kasabay nito ay pagbutihin ang iyong sariling mga kasanayan?

Upang gawing simple ang lahat hangga't maaari, pagkatapos ay mayroon lamang dalawang paraan upang radikal na mapabuti ang isang bagay sa pagganap ng database:
1) Malawak na landas - pinapataas namin ang mga mapagkukunan, binabago ang pagsasaayos;
2) Intensive path - pag-optimize ng query

Dahil, inuulit ko, sa oras na iyon ay hindi na malinaw kung ano pa ang dapat baguhin sa kahilingan na mapabilis, ang landas ay pinili - pagbabago sa disenyo ng mesa.

Kaya, ang pangunahing tanong ay lumitaw: ano at paano tayo magbabago?

Mga paunang kondisyon

Una, mayroong ERD na ito (ipinapakita sa isang kondisyon na pinasimple na paraan):
Happy Party o ilang linya ng mga alaala tungkol sa pagkilala sa partitioning sa PostgreSQL10
Pangunahing mga tampok:

  1. many-to-many na relasyon
  2. ang talahanayan ay mayroon nang potensyal na partition key

Orihinal na kahilingan:

SELECT
            p."PARAMETER_ID" as  parameter_id,
            pc."PC_NAME" AS pc_name,
            pc."CUSTOMER_PARTNUMBER" AS customer_partnumber,
            w."LASERMARK" AS lasermark,
            w."LOTID" AS lotid,
            w."REPORTED_VALUE" AS reported_value,
            w."LOWER_SPEC_LIMIT" AS lower_spec_limit,
            w."UPPER_SPEC_LIMIT" AS upper_spec_limit,
            p."TYPE_CALCUL" AS type_calcul,
            s."SHIPMENT_NAME" AS shipment_name,
            s."SHIPMENT_DATE" AS shipment_date,
            extract(year from s."SHIPMENT_DATE") AS year,
            extract(month from s."SHIPMENT_DATE") as month,
            s."REPORT_NAME" AS report_name,
            p."SPARAM_NAME" AS SPARAM_name,
            p."CUSTOMERPARAM_NAME" AS customerparam_name
        FROM data w INNER JOIN shipment s ON s."SHIPMENT_ID" = w."SHIPMENT_ID"
             INNER JOIN parameters p ON p."PARAMETER_ID" = w."PARAMETER_ID"
             INNER JOIN shipment_pc sp ON s."SHIPMENT_ID" = sp."SHIPMENT_ID"
             INNER JOIN pc pc ON pc."PC_ID" = sp."PC_ID"
             INNER JOIN ( SELECT w2."LASERMARK" , MAX(s2."SHIPMENT_DATE") AS "SHIPMENT_DATE"
                          FROM shipment s2 INNER JOIN data w2 ON s2."SHIPMENT_ID" = w2."SHIPMENT_ID" 
                          GROUP BY w2."LASERMARK"
                         ) md ON md."SHIPMENT_DATE" = s."SHIPMENT_DATE" AND md."LASERMARK" = w."LASERMARK"
        WHERE 
             s."SHIPMENT_DATE" >= '2018-07-01' AND s."SHIPMENT_DATE" <= '2018-09-30' ;

Mga resulta ng pagpapatupad sa database ng pagsubok:
gastos : 502 997.55
Oras ng pagpapatupad: 505 segundo.

Ano ang nakikita natin? Isang regular na kahilingan, batay sa isang time slice.
Gawin natin ang pinakasimpleng lohikal na palagay: kung may sample ng time slice, makakatulong ba ito sa atin? Iyan ay tama - partitioning.

Anong section?

Sa unang sulyap, ang pagpipilian ay halata - declarative partitioning ng "shipment" table gamit ang "SHIPMENT_DATE" key (tumalon ng masyadong malayo sa unahan - sa huli ito ay naging isang maliit na mali sa produksyon).

Paano mag partition?

Ang tanong na ito ay hindi rin masyadong mahirap. Sa kabutihang palad, sa PostgreSQL 10, mayroon na ngayong mekanismo ng paghahati ng tao.
Kaya:

  1. Mag-save ng dump ng source table - pg_dump source_table
  2. Tanggalin ang orihinal na talahanayan - drop table source_table
  3. Gumawa ng parent table na may range partitioning - lumikha ng talahanayan source_table
  4. Lumikha ng mga seksyon - lumikha ng talahanayan source_table, lumikha ng index
  5. I-import ang dump na ginawa sa hakbang 1 - pg_restore

Mga script para sa paghahati

Para sa pagiging simple at kaginhawahan, ang mga hakbang 2,3,4 ay pinagsama sa isang script.

Kaya:
Mag-save ng dump ng source table

pg_dump postgres --file=/dump/shipment.dmp --format=c --table=shipment --verbose > /dump/shipment.log 2>&1

Tanggalin ang source table + Gumawa ng parent table na may range partitioning + Gumawa ng partition

--create_partition_shipment.sql
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;
current_year varchar ;
current_month varchar ;
begin_year varchar ;
begin_month varchar ;
next_year varchar ;
next_month varchar ;
first_flag boolean ;
i integer ;
begin
  RAISE NOTICE 'CREATE TEMPORARY TABLE FOR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;

  RAISE NOTICE 'DROP TABLE shipment';
  drop table shipment cascade ;
  
  CREATE TABLE public.shipment
  (
    "SHIPMENT_ID" integer NOT NULL DEFAULT nextval('shipment_shipment_id_seq'::regclass),
    "SHIPMENT_NAME" character varying(30) COLLATE pg_catalog."default",
    "SHIPMENT_DATE" timestamp without time zone,
    "REPORT_NAME" character varying(40) COLLATE pg_catalog."default"
  )
  PARTITION BY RANGE ("SHIPMENT_DATE")
  WITH (
      OIDS = FALSE
  )
  TABLESPACE pg_default;

  RAISE NOTICE 'CREATE PARTITIONS FOR TABLE shipment';

  current_year:='0';
  current_month:='0';

  begin_year := '0' ;
  begin_month := '0'  ;
  next_year := '0' ;
  next_month := '0'  ;

  FOR rec_shipment_date IN SELECT * FROM tmp_shipment_date LOOP
      
      RAISE NOTICE 'SHIPMENT_DATE=%',rec_shipment_date."SHIPMENT_DATE";
      
      current_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE");
      current_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE") ; 

      IF to_number(current_month,'99') < 10 THEN
        current_month := '0'||current_month ; 
      END IF ;

      --Init borders
      IF   begin_year = '0' THEN
       first_flag := true ; --first time flag
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;

      -- Check current date into borders NOT for First time
      IF to_date( current_year||'.'||current_month, 'YYYY.MM') >= to_date( begin_year||'.'||begin_month, 'YYYY.MM') AND 
         to_date( current_year||'.'||current_month, 'YYYY.MM') < to_date( next_year||'.'||next_month, 'YYYY.MM') AND 
         NOT first_flag 
      THEN
         CONTINUE ; 
      ELSE
       --NEW borders only for second and after time 
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;      

      partition_name := 'shipment_shipment_date_'||begin_year||'-'||begin_month||'-01-'|| next_year||'-'||next_month||'-01'  ;
 
     EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF shipment FOR VALUES FROM ( %L ) TO ( %L )  ' , current_year||'-'||current_month||'-01' , next_year||'-'||next_month||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      --Drop first time flag
      first_flag := false ;
   
  END LOOP;

end
$$;

Ini-import ang dump

pg_restore -d postgres --data-only --format=c --table=shipment --verbose  shipment.dmp > /tmp/data_dump/shipment_restore.log 2>&1

Sinusuri ang mga resulta ng partitioning

Ano ang mayroon tayo bilang isang resulta? Ang buong teksto ng plano sa pagpapatupad ay malaki at nakakainip, kaya medyo posible na limitahan ang iyong sarili sa mga huling numero.

Ay

Gastos: 502 997.55
Oras ng pagpapatupad: 505 segundo.

Ay naging

Gastos: 77 872.36
Oras ng pagpapatupad: 79 segundo.

Medyo magandang resulta. Nabawasan ang gastos at oras ng pagpapatupad. Kaya, ang paggamit ng partitioning ay nagbibigay ng inaasahang epekto at, sa pangkalahatan, walang mga sorpresa.

Gawing masaya ang customer

Ang mga resulta ng pagsubok ay ipinakita sa customer para sa pagsusuri. At pagkatapos itong suriin, binigyan sila ng medyo hindi inaasahang hatol: "Mahusay, hatiin ang talahanayan ng "data."

Oo, ngunit sinuri namin ang isang ganap na naiibang talahanayan ng "pagpapadala"; ang talahanayan ng "data" ay walang field na "SHIPMENT_DATE".

Walang problema, magdagdag, baguhin. Ang pangunahing bagay ay ang customer ay nasiyahan sa resulta, ang mga detalye ng pagpapatupad ay hindi partikular na mahalaga.

Paghati sa pangunahing talahanayan na "data"

Sa pangkalahatan, walang partikular na paghihirap ang lumitaw. Bagaman, ang algorithm ng partitioning, siyempre, ay medyo nagbago.

Pagdaragdag ng column na "SHIPMENT_DATA" sa talahanayan ng "data".

psql -h хост -U Π±Π°Π·Π° -d ΡŽΠ·Π΅Ρ€
=> ALTER TABLE data ADD COLUMN "SHIPMENT_DATE" timestamp without time zone ;

Punan ang mga halaga ng column na "SHIPMENT_DATA" sa talahanayan ng "data" na may mga halaga ng column ng parehong pangalan mula sa talahanayan ng "shipment"

-----------------------------
--update_data.sql
--updating for altered table "data" to values of "shipment_data" from the table "shipment"
--version 1.0
do language plpgsql $$
declare 
rec_shipment_data RECORD ;
shipment_date timestamp without time zone ; 
row_count integer ;
total_rows integer ;
begin

  select count(*) into total_rows from shipment ; 
  RAISE NOTICE 'Total %',total_rows;
  row_count:= 0 ;

  FOR rec_shipment_data IN SELECT * FROM shipment LOOP

   update data set "SHIPMENT_DATE" = rec_shipment_data."SHIPMENT_DATE" where "SHIPMENT_ID" = rec_shipment_data."SHIPMENT_ID";
   
   row_count:=  row_count +1 ;
   RAISE NOTICE 'row count = % , from %',row_count,total_rows;
  END LOOP;

end
$$;

Mag-save ng dump ng talahanayan ng "data".

pg_dump postgres --file=/dump/data.dmp --format=c --table=data --verbose > /dump/data.log 2>&1</source

Gawin muli ang naka-partition na talahanayan na "data"

--create_partition_data.sql
--create partitions for the table "wafer data" by range column "shipment_data" with one month duration
--version 1.0
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;
current_year varchar ;
current_month varchar ;
begin_year varchar ;
begin_month varchar ;
next_year varchar ;
next_month varchar ;
first_flag boolean ;
i integer ;

begin

  RAISE NOTICE 'CREATE TEMPORARY TABLE FOR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;


  RAISE NOTICE 'DROP TABLE data';
  drop table data cascade ;


  RAISE NOTICE 'CREATE PARTITIONED TABLE data';
  
  CREATE TABLE public.data
  (
    "RUN_ID" integer,
    "LASERMARK" character varying(20) COLLATE pg_catalog."default" NOT NULL,
    "LOTID" character varying(80) COLLATE pg_catalog."default",
    "SHIPMENT_ID" integer NOT NULL,
    "PARAMETER_ID" integer NOT NULL,
    "INTERNAL_VALUE" character varying(75) COLLATE pg_catalog."default",
    "REPORTED_VALUE" character varying(75) COLLATE pg_catalog."default",
    "LOWER_SPEC_LIMIT" numeric,
    "UPPER_SPEC_LIMIT" numeric , 
    "SHIPMENT_DATE" timestamp without time zone
  )
  PARTITION BY RANGE ("SHIPMENT_DATE")
  WITH (
    OIDS = FALSE
  )
  TABLESPACE pg_default ;


  RAISE NOTICE 'CREATE PARTITIONS FOR TABLE data';

  current_year:='0';
  current_month:='0';

  begin_year := '0' ;
  begin_month := '0'  ;
  next_year := '0' ;
  next_month := '0'  ;
  i := 1;

  FOR rec_shipment_date IN SELECT * FROM tmp_shipment_date LOOP
      
      RAISE NOTICE 'SHIPMENT_DATE=%',rec_shipment_date."SHIPMENT_DATE";
      
      current_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE");
      current_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE") ; 

      --Init borders
      IF   begin_year = '0' THEN
       RAISE NOTICE '***Init borders';
       first_flag := true ; --first time flag
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;

--      RAISE NOTICE 'current_year=% , current_month=% ',current_year,current_month;
--      RAISE NOTICE 'begin_year=% , begin_month=% ',begin_year,begin_month;
--      RAISE NOTICE 'next_year=% , next_month=% ',next_year,next_month;

      -- Check current date into borders NOT for First time

      RAISE NOTICE 'Current data = %',to_char( to_date( current_year||'.'||current_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Begin data = %',to_char( to_date( begin_year||'.'||begin_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Next data = %',to_char( to_date( next_year||'.'||next_month, 'YYYY.MM'), 'YYYY.MM');

      IF to_date( current_year||'.'||current_month, 'YYYY.MM') >= to_date( begin_year||'.'||begin_month, 'YYYY.MM') AND 
         to_date( current_year||'.'||current_month, 'YYYY.MM') < to_date( next_year||'.'||next_month, 'YYYY.MM') AND 
         NOT first_flag 
      THEN
         RAISE NOTICE '***CONTINUE';
         CONTINUE ; 
      ELSE
       --NEW borders only for second and after time 
       RAISE NOTICE '***NEW BORDERS';
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;


      END IF;      

      IF to_number(current_month,'99') < 10 THEN
        current_month := '0'||current_month ; 
      END IF ;

      IF to_number(begin_month,'99') < 10 THEN
        begin_month := '0'||begin_month ; 
      END IF ;

      IF to_number(next_month,'99') < 10 THEN
        next_month := '0'||next_month ; 
      END IF ;

      RAISE NOTICE 'current_year=% , current_month=% ',current_year,current_month;
      RAISE NOTICE 'begin_year=% , begin_month=% ',begin_year,begin_month;
      RAISE NOTICE 'next_year=% , next_month=% ',next_year,next_month;

      partition_name := 'data_'||begin_year||begin_month||'01_'||next_year||next_month||'01'  ;

      RAISE NOTICE 'PARTITION NUMBER % , TABLE NAME =%',i , partition_name;
      
      EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF data FOR VALUES FROM ( %L ) TO ( %L )  ' , begin_year||'-'||begin_month||'-01' , next_year||'-'||next_month||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_parameter_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID", "PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_lasermark_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("LASERMARK" COLLATE pg_catalog."default") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_parameter_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_date_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

      --Drop first time flag
      first_flag := false ;

  END LOOP;
end
$$;

I-load ang dump na ginawa sa hakbang 3.

pg_restore -h хост -ΡŽΠ·Π΅Ρ€ -d Π±Π°Π·Π° --data-only --format=c --table=data --verbose  data.dmp > data_restore.log 2>&1

Gumawa ng hiwalay na seksyon para sa lumang data

---------------------------------------------------
--create_partition_for_old_dates.sql
--create partitions for keeping old dates 
--version 1.0
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;

begin

      SELECT min("SHIPMENT_DATE") AS min_date INTO rec_shipment_date from data ;

      RAISE NOTICE 'Old date is %',rec_shipment_date.min_date ;

      partition_name := 'data_old_dates'  ;

      RAISE NOTICE 'PARTITION NAME IS %',partition_name;

      EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF data FOR VALUES FROM ( %L ) TO ( %L )  ' , '1900-01-01' , 
              to_char( rec_shipment_date.min_date,'YYYY')||'-'||to_char(rec_shipment_date.min_date,'MM')||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_parameter_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID", "PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_lasermark_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("LASERMARK" COLLATE pg_catalog."default") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_parameter_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_date_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

end
$$;

Mga huling resulta:

Ay
Gastos: 502 997.55
Oras ng pagpapatupad: 505 segundo.

Ay naging
Gastos: 68 533.70
Oras ng pagpapatupad: 69 segundo

Karapat-dapat, medyo karapat-dapat. At kung isasaalang-alang na sa kahabaan ng paraan, nagtagumpay kami sa higit pa o mas kaunting pag-master ng mekanismo ng partitioning sa PostgreSQL 10 - isang mahusay na resulta.

Lyrical digression

Posible bang gumawa ng mas mahusay - OO, KAYA MO!Upang gawin ito kailangan mong gumamit ng MATERIALIZED VIEW.
GUMAWA NG MATERIALIZED VIEW LASERMARK_VIEW

CREATE MATERIALIZED VIEW LASERMARK_VIEW 
AS
SELECT w."LASERMARK" , MAX(s."SHIPMENT_DATE") AS "SHIPMENT_DATE"
FROM shipment s INNER JOIN data w ON s."SHIPMENT_ID" = w."SHIPMENT_ID" 
GROUP BY w."LASERMARK" ;

CREATE INDEX lasermark_vw_shipment_date_ind on lasermark_view USING btree ("SHIPMENT_DATE") TABLESPACE pg_default;
analyze lasermark_view ;

Muli naming isinusulat muli ang kahilingan:
Query gamit ang materialized view

SELECT
            p."PARAMETER_ID" as  parameter_id,
            pc."PC_NAME" AS pc_name,
            pc."CUSTOMER_PARTNUMBER" AS customer_partnumber,
            w."LASERMARK" AS lasermark,
            w."LOTID" AS lotid,
            w."REPORTED_VALUE" AS reported_value,
            w."LOWER_SPEC_LIMIT" AS lower_spec_limit,
            w."UPPER_SPEC_LIMIT" AS upper_spec_limit,
            p."TYPE_CALCUL" AS type_calcul,
            s."SHIPMENT_NAME" AS shipment_name,
            s."SHIPMENT_DATE" AS shipment_date,
            extract(year from s."SHIPMENT_DATE") AS year,
            extract(month from s."SHIPMENT_DATE") as month,
            s."REPORT_NAME" AS report_name,
            p."STC_NAME" AS STC_name,
            p."CUSTOMERPARAM_NAME" AS customerparam_name
        FROM data w INNER JOIN shipment s ON s."SHIPMENT_ID" = w."SHIPMENT_ID"
             INNER JOIN parameters p ON p."PARAMETER_ID" = w."PARAMETER_ID"
             INNER JOIN shipment_pc sp ON s."SHIPMENT_ID" = sp."SHIPMENT_ID"
             INNER JOIN pc pc ON pc."PC_ID" = sp."PC_ID"
             INNER JOIN LASERMARK_VIEW md ON md."SHIPMENT_DATE" = s."SHIPMENT_DATE" AND md."LASERMARK" = w."LASERMARK"
        WHERE 
              s."SHIPMENT_DATE" >= '2018-07-01' AND s."SHIPMENT_DATE" <= '2018-09-30';

At nakakakuha kami ng isa pang resulta:
Ay
Gastos: 502 997.55
Oras ng pagpapatupad: 505 segundo

Ay naging
Gastos: 42 481.16
Oras ng pagpapatupad: 43 segundo.

Bagaman, siyempre, ang gayong magandang resulta ay mapanlinlang; kailangang i-refresh ang mga ideya. Kaya't ang kabuuang oras upang makatanggap ng data ay hindi makakatulong nang malaki. Ngunit bilang isang eksperimento ito ay medyo kawili-wili.

Actually, as it turned out, salamat ulit asmm at Habru!- Maaaring pagbutihin pa ang query.

afterword

Kaya, ang customer ay nasiyahan. AT kailangan samantalahin ang sitwasyon.

Bagong gawain: Ano ang maaari mong maisip upang palalimin at palawakin?

At pagkatapos ay naaalala ko - guys, wala kaming pagsubaybay sa aming mga database ng PostgreSQL.

Hand on heart, mayroon pa ring ilang pagsubaybay sa anyo ng Cloud Watch sa AWS. Ngunit ano ang pakinabang ng pagsubaybay na ito para sa DBA? Sa pangkalahatan, halos wala.

Kung may pagkakataon kang gumawa ng isang bagay na kapaki-pakinabang at kawili-wili para sa iyong sarili, hindi mo maaaring samantalahin ang pagkakataong ito...
PARA SA

Happy Party o ilang linya ng mga alaala tungkol sa pagkilala sa partitioning sa PostgreSQL10

Ganito tayo nakarating sa pinakakawili-wiling bahagi:

Disyembre 3, 2018.
Paggawa ng desisyon na simulan ang pagsasaliksik sa mga magagamit na kakayahan para sa pagsubaybay sa pagganap ng mga query sa PostgreSQL.

Ngunit iyon ay isang ganap na naiibang kuwento.

Itutuloy…

Pinagmulan: www.habr.com

Magdagdag ng komento