Happy Party ose disa rreshta-kujtime mbi njohjen me seksionimin në PostgreSQL10

Parathënie, ose si lindi ideja e particionimit

Fillimi i historisĂ« Ă«shtĂ« kĂ«tu: A tĂ« kujtohet si filloi gjithçka. Gjithçka ishte pĂ«r herĂ« tĂ« parĂ« dhe pĂ«rsĂ«ri nga e para. Pasi pothuajse tĂ« gjitha burimet pĂ«r optimizimin e kĂ«rkesĂ«s, nĂ« atĂ« moment, ishin shteruar, u ngrit pyetja — çfarĂ« bĂ«jmĂ« mĂ« tej? KĂ«shtu edhe lindi ideja e particionimit.

Happy Party ose disa rreshta-kujtime mbi njohjen me seksionimin në PostgreSQL10

Një digresion lirik:
PikĂ«risht “nĂ« atĂ« moment”, sepse siç doli, kishte ende rezerva tĂ« pashfrytĂ«zuara pĂ«r optimizim. Faleminderit asmm dhe Habr-it!

Pra, si mund ta bëjmë klientin disi të kënaqur dhe njëkohësisht të përmirësojmë aftësitë tona?

Nëse e thjeshtojmë gjithçka në maksimum, atëherë ka vetëm dy mënyra për të përmirësuar rrënjësisht performancën e bazës së të dhënave:
1) Rruga ekstensivĐ” — shtojmĂ« burimet, ndryshojmĂ« konfigurimin;
2) Rruga intensive — optimizimi i kĂ«rkesave

Meqë, siç e përsëris, në atë moment nuk ishte më e qartë se çfarë tjetër mund të ndryshohej në kërkesë për ta përshpejtuar, u zgjodh rruga e ndryshimit të dizajnit të tabelave.

Pra, lind pyetja kryesore — çfarĂ« dhe si do tĂ« ndryshojmĂ«?

Kushtet fillestare

Së pari, kemi një ERD të tillë (të paraqitur në mënyrë të thjeshtuar me kusht):
Happy Party ose disa rreshta-kujtime mbi njohjen me seksionimin në PostgreSQL10
Karakteristikat kryesore:

  1. marrĂ«dhĂ«nie “shumĂ« me shumĂ«â€
  2. tabela tashmë ka një çelës të mundshëm particionimi

Kërkesa fillestare:

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' ;

Rezultatet e ekzekutimit në bazën e të dhënave testuese:
Kosto : 502 997.55
Koha e ekzekutimit: 505 sekonda.

ÇfarĂ« shohim? NjĂ« kĂ«rkesĂ« e zakonshme, sipas njĂ« intervali kohor.
BĂ«jmĂ« njĂ« supozim logjik shumĂ« tĂ« thjeshtĂ«: nĂ«se kemi njĂ« mostĂ«r tĂ« njĂ« prerjeje kohore, çfarĂ« do tĂ« na ndihmojĂ«? SaktĂ« — particionimi.

ÇfarĂ« tĂ« particionohet?

NĂ« pamje tĂ« parĂ«, zgjedhja Ă«shtĂ« e qartĂ« — particionimi deklarativ i tabelĂ«s «shipment» sipas çelĂ«sit «SHIPMENT_DATE» (duke e paraprirĂ« shumĂ« ngjarjet — nĂ« fund nĂ« production doli pak ndryshe).

Si të particionohet?

Edhe kjo pyetje nuk është shumë e vështirë. Për fat, në PostgreSQL 10 tani ekziston një mekanizëm njerëzor particionimi.
Pra:

  1. RuajmĂ« dump-in e tabelĂ«s burimore — pg_dump source_table
  2. FshijmĂ« tabelĂ«n burimore — drop table source_table
  3. KrijojmĂ« tabelĂ«n prind me particionim sipas intervalit — create table source_table
  4. KrijojmĂ« particionet — create table source_table, create index
  5. ImportojmĂ« dump-in e krijuar nĂ« hapin 1 — pg_restore

Skriptet për particionim

Për thjeshtësi dhe lehtësi përdorimi, hapat 2, 3, 4 u bashkuan në një skript të vetëm.

Pra:
Ruajmë dump-in e tabelës burimore

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

Fshijmë tabelën burimore + Krijojmë tabelën prind me particionim sipas intervalit + Krijojmë particionet

--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') = 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
$$;

Importojmë dump-in

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

Kontrollojmë rezultatet e particionimit

ÇfarĂ« kemi si pĂ«rfundim? Teksti i plotĂ« i planit tĂ« ekzekutimit Ă«shtĂ« i gjatĂ« dhe i mĂ«rzitshĂ«m, prandaj mund tĂ« kufizohemi te shifrat pĂ«rfundimtare.

Ishte

Kostoja: 502 997.55
Koha e ekzekutimit: 505 sekonda.

U bë

Kostoja: 77 872.36
Koha e ekzekutimit: 79 sekonda.

Një rezultat mjaft i mirë. Ulëm koston dhe kohën e ekzekutimit. Kështu, përdorimi i particionimit jep efektin e pritur dhe, në përgjithësi, pa surpriza.

Ta gëzojmë klientin

Rezultatet e testimit iu paraqitën klientit për shqyrtim. Dhe pas njohjes me to, u dha një verdikt disi i papritur: «Shkëlqyeshëm, particiononi tabelën «data»».

Po, por ne po studionim një tabelë krejt tjetër, «shipment»; tabela «data» nuk ka fushën «SHIPMENT_DATE».

Nuk është problem, shtojeni, ndryshojeni. Kryesorja është që klienti të jetë i kënaqur me rezultatin përfundimtar; hollësitë e zbatimit nuk janë edhe aq të rëndësishme.

Particionojmë tabelën kryesore «data»

Në përgjithësi, nuk pati ndonjë vështirësi të veçantë. Megjithatë, algoritmi i particionimit, natyrisht, ndryshoi disi.

Shtojmë kolonën «SHIPMENT_DATA» në tabelën «data»

psql -h host -U bazë -d përdorues
=> ALTER TABLE data ADD COLUMN "SHIPMENT_DATE" timestamp without time zone ;

Plotësojmë vlerat e kolonës «SHIPMENT_DATA» në tabelën «data» me vlerat e kolonës me të njëjtin emër nga tabela «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
$$;

Ruajmë dump-in e tabelës «data»

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

Rikrijojmë tabelën e particionuar «data»

--create_partition_data.sql
--krijo particione për tabelën "wafer data" sipas kolonës së intervalit "shipment_data" me kohëzgjatje një mujore
--versioni 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 'KRIJO TABELË TË PËRKOHSHME PËR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;


  RAISE NOTICE 'FSHI TABELËN data';
  drop table data cascade ;


  RAISE NOTICE 'KRIJO TABELËN E PARTICIONUAR 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 'KRIJO PARTICIONE PËR TABELËN 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") ; 

      --Inicializo kufijtë
      IF   begin_year = '0' THEN
       RAISE NOTICE '***Inicializo kufijtë';
       first_flag := true ; --flamur për herën e parë
       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;

      -- Kontrollo datën aktuale brenda kufijve, JO për herën e parë

      RAISE NOTICE 'Të dhënat aktuale = %',to_char( to_date( current_year||'.'||current_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Të dhënat e fillimit = %',to_char( to_date( begin_year||'.'||begin_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Të dhënat pasuese = %',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 '***VAZHDO';
         CONTINUE ; 
      ELSE
       --Kufij të RINJ vetëm nga hera e dytë e tutje 
       RAISE NOTICE '***KUFIJ TË RINJ';
       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 'NUMRI I PARTICIONIT % , EMRI I TABELËS =%',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 'EMRI I INDEKSIT =%',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 'EMRI I INDEKSIT =%',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 'EMRI I INDEKSIT =%',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 'EMRI I INDEKSIT =%',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 'EMRI I INDEKSIT =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

      --Hiq flamurin e herës së parë
      first_flag := false ;

  END LOOP;
end
$$;

Ngarkojmë dump-in e krijuar në hapin 3.

pg_restore -h Ń…ĐŸŃŃ‚ -юзДр -d база --data-only --format=c --table=data --verbose  data.dmp > data_restore.log 2>&1

Krijojmë një seksion të veçantë për të dhënat e vjetra

---------------------------------------------------
--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
$$;

Rezultatet përfundimtare:

Ishte
Kostoja: 502 997.55
Koha e ekzekutimit: 505 sekonda.

U bë
Kostoja: 68 533.70
Koha e ekzekutimit: 69 sekonda

ShumĂ« mirĂ«, vĂ«rtet shumĂ« mirĂ«. Sidomos duke pasur parasysh se gjatĂ« procesit arritĂ«m tĂ« kuptojmĂ« pak a shumĂ« edhe mekanizmin e particionimit nĂ« PostgreSQL 10 — rezultat i shkĂ«lqyer.

Një hapje lirikë

A mund tĂ« bĂ«het edhe mĂ« mirĂ« — PO, MUND TË BËHET!PĂ«r kĂ«tĂ« duhet tĂ« pĂ«rdoret MATERIALIZED VIEW.
CREATE 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 ;

E rishkruajmë edhe një herë kërkesën:
Kërkesë duke përdorur 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';

Dhe marrim edhe një rezultat përfundimtar:
Ishte
Kostoja: 502 997.55
Koha e ekzekutimit: 505 sekonda

U bë
Kostoja: 42 481.16
Koha e ekzekutimit: 43 sekonda.

Megjithëse, sigurisht, ky rezultat kaq premtues është mashtrues, sepse pamjet duhen rifreskuar. Kështu që koha përfundimtare e marrjes së të dhënave nuk do të ndihmojë edhe aq shumë. Por si eksperiment, është mjaft interesante.

Në fakt, siç doli, edhe një herë faleminderit asmm dhe Habr !- kërkesa mund të përmirësohet edhe më tej.

Pasthënie

Pra, klienti është i kënaqur. Dhe të shtoni një kolonë të re - asnjë problem, më poshtë është një zgjidhje e thjeshtë një-linjëshe. Zgjidhja është evolucioni i skemës! të përfitojmë nga situata.

DetyrĂ« e re: ÇfarĂ« mund tĂ« shpikim qĂ« ta thellojmĂ« dhe zgjerojmĂ«?

Dhe kĂ«tu kujtojmĂ« — djema, ne nĂ« fakt nuk kemi monitorim tĂ« bazave tona tĂ« tĂ« dhĂ«nave PostgreSQL.

Të themi të drejtën, një lloj monitorimi në formën e Cloud Watch në AWS gjithsesi ekziston. Por çfarë dobie ka ky monitorim për DBA? Në thelb, pothuajse asnjë.

NĂ«se tĂ« Ă«shtĂ« dhĂ«nĂ« mundĂ«sia tĂ« bĂ«sh diçka tĂ« dobishme dhe interesante edhe pĂ«r veten, nuk mund tĂ« mos e shfrytĂ«zosh njĂ« mundĂ«si tĂ« tillĂ« 

SEPSE

Happy Party ose disa rreshta-kujtime mbi njohjen me seksionimin në PostgreSQL10

Kështu iu afruam pjesës më interesante:

3 Dhjetor 2018.
Marrja e vendimit për të nisur punën për studimin e mundësive ekzistuese të monitorimit të performancës së kërkesave PostgreSQL.

Por kjo është tashmë një histori krejt tjetër.

Vazhdimi pason


Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster