Happy Party eller nÄgra rader med minnen om att lÀra sig sektionering i PostgreSQL10.

Förord eller hur idén om sektionering uppstod

Början av historien hÀr: Kommer du ihÄg hur allt började? Allt var första gÄngen och pÄ nytt. Efter att nÀstan alla resurser för optimering av förfrÄgan vid den tidpunkten hade uttömts, uppstod frÄgan - vad hÀnder hÀrnÀst? SÄ föddes idén om sektionering.

Happy Party eller nÄgra rader med minnen om att lÀra sig sektionering i PostgreSQL10.

Ett lyriskt avsnitt:
Just 'vid den tidpunkten', för att som det visade sig, fanns det outnyttjade reserver för optimering. Tack asmm och Habr !

SÄ hur kan man göra kunden lite lyckligare och samtidigt förbÀttra sina egna fÀrdigheter?

Om man förenklar allt, finns det i grunden tvÄ sÀtt att radikalt förbÀttra databasens prestanda:
1) Extensiv vÀg - öka resurser, Àndra konfiguration;
2) Intensiv vÀg - optimera förfrÄgningar

Eftersom det, som jag upprepar, vid den tidpunkten redan var oklart vad som mer skulle Àndras i förfrÄgan för att öka hastigheten, valdes vÀgen - Àndringar i tabellens design.

SÄ - den huvudsakliga frÄgan uppstÄr - vad och hur ska vi förÀndra?

Ursprungliga förhÄllanden

För det första, hÀr Àr en sÄdan ERD (visas förenklat):
Happy Party eller nÄgra rader med minnen om att lÀra sig sektionering i PostgreSQL10.
Huvudfunktioner:

  1. relationer ‘mĂ„nga till mĂ„nga’
  2. tabellen har redan en potentiell sektioneringsnyckel

Ursprunglig förfrÄgan:

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

Resultat av körningen pÄ testdatabasen:
Kostnad : 502 997.55
Körningstid: 505 sekunder.

Vad ser vi? En vanlig förfrÄgan, baserat pÄ tidsintervallet.
Vi gör en enkel logisk slutsats: om det finns ett urval av en tidsram, hjĂ€lper det oss? RĂ€tt — partitionering.

Vad ska partitioneras?

Vid första anblick verkar valet uppenbart — deklarativ partitionering av tabellen "shipment" baserat pĂ„ nyckeln "SHIPMENT_DATE" (för att gĂ„ lite för lĂ„ngt fram — i slutĂ€ndan blev det inte riktigt sĂ„ i produktion).

Hur partitionerar man?

Denna frÄga Àr inte heller sÀrskilt svÄr. Tack och lov, i PostgreSQL 10 finns det nu ett mÀnskligt vÀnligt partitioneringssystem.
SĂ„:

  1. Spara en dump av den ursprungliga tabellen — pg_dump source_table
  2. Ta bort den ursprungliga tabellen — drop table source_table
  3. Skapa en förĂ€ldratabell med partitionering efter intervall — create table source_table
  4. Skapa partitioner — create table source_table, create index
  5. Importera dumpen som skapades i steg 1 — pg_restore

Skript för partitionering

För enkelhetens skull har steg 2, 3, 4 sammanfogats i ett enda skript.

SĂ„:
Spara en dump av den ursprungliga tabellen

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

Ta bort den ursprungliga tabellen + Skapa en förÀldratabell med partitionering efter intervall + Skapa partitioner

--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 'SKAPA TILLFÄLIG TABELL FÖR LEVERANS_DATUM';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;

  RAISE NOTICE 'TA BORT TABELL LEVERANS';
  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 'SKAPA PARTITIONER FÖR TABELL LEVERANS';

  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 'LEVERANS_DATUM=%',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
       --NYA grÀnser endast för andra gÄngen och framÄt
       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 'INDEXNAMN =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      --Ta bort första gÄngen flagga
      first_flag := false ;
   
  END LOOP;

end
$$;

Importera dump

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

Kontrollera resultaten av partitioneringen

Vad har vi dÄ i resultat? Den fullstÀndiga texten av planen Àr stor och trÄkig, sÄ det rÀcker att begrÀnsa sig till de slutliga siffrorna.

Det var

Kostnad: 502 997.55
Utförande tid: 505 sekunder.

Det blev

Kostnad: 77 872.36
Utförande tid: 79 sekunder.

Ett ganska bra resultat. Vi minskade kostnaden och utförandetiden. SĂ„ledes ger anvĂ€ndningen av partitionering det förvĂ€ntade resultatet och över lag — utan överraskningar.

GlÀdja bestÀllaren

Testresultaten presenterades för bestÀllaren för granskning. Efter genomgÄngen kom en nÄgot ovÀntad dom: "UtmÀrkt, partitionera tabellen 'data'."

Ja, men vi har ju studerat helt andra tabellen 'shipment', tabellen 'data' har inte fÀltet 'SHIPMENT_DATE'.

Ingen fara, lÀgg till, Àndra. Det viktigaste Àr att bestÀllaren Àr nöjd med vad som kommer att bli resultatet, detaljerna i implementeringen Àr inte sÄ viktiga.

Vi partitionerar huvudtabellen 'data'

PĂ„ det hela ingen sĂ€rskild svĂ„righet dök upp. Även om algoritmen för partitionering sjĂ€lvklart har förĂ€ndrats nĂ„got.

Vi lÀgger till kolumnen 'SHIPMENT_DATE' i tabellen 'data'

psql -h vÀrd -U databas -d anvÀndare
=> ALTER TABLE data ADD COLUMN "SHIPMENT_DATE" timestamp without time zone ;

Vi fyller kolumnens vÀrden 'SHIPMENT_DATE' i tabellen 'data' med vÀrdena frÄn den namngivna kolumnen i tabellen 'shipment'

-----------------------------
--update_data.sql
--uppdaterar för den Àndrade tabellen "data" till vÀrden av "shipment_data" frÄn tabellen "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
$$;

Vi sparar dumpen av tabellen 'data'

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

Vi Äterskapar den partitionerade tabellen 'data'

--create_partition_data.sql
--skapa partitioner för tabellen "wafer data" efter intervallet "shipment_data" med en mÄnads varaktighet
--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 'SKAPA TILLFÄLLIG TABELL FÖR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;


  RAISE NOTICE 'RADERA TABELL data';
  drop table data cascade ;


  RAISE NOTICE 'SKAPA PARTITIONERAD TABELL 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 'SKAPA PARTITIONER FÖR TABELL 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 grÀnser
      IF   begin_year = '0' THEN
       RAISE NOTICE '***Init grÀnser';
       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;

      -- Kontrollera aktuellt datum i grÀnser INTE för första gÄngen

      RAISE NOTICE 'Aktuella data = %',to_char( to_date( current_year||'.'||current_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Börja data = %',to_char( to_date( begin_year||'.'||begin_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'NĂ€sta 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 '***FortsÀtt';
         CONTINUE ; 
      ELSE
       --NYA grÀnser endast för andra och efterföljande gÄnger 
       RAISE NOTICE '***NYA GRÄNSER';
       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 'PARTITIONNUMMER % , TABELLNAMN =%',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 'INDEXNAMN =%',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 'INDEXNAMN =%',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 'INDEXNAMN =%',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 'INDEXNAMN =%',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 'INDEXNAMN =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

      --Ta bort första tidsflaggan
      first_flag := false ;

  END LOOP;
end
$$;

Laddar upp dumpfilen som skapades i steg 3.

pg_restore -h vÀrd -user -d databas --data-only --format=c --table=data --verbose data.dmp > data_restore.log 2>&1

Skapar en separat sektion för gamla data

---------------------------------------------------
--create_partition_for_old_dates.sql
--skapa partitioner för att behÄlla gamla datum
--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 'Gammalt datum Àr %',rec_shipment_date.min_date ;

      partition_name := 'data_old_dates'  ;

      RAISE NOTICE 'PARTITIONSNAMNET ÄR %',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
$$;

Slutresultat:

Det var
Kostnad: 502 997.55
Körningstid: 505 sekunder.

Det blev
Kostnad: 68 533.70
Utförande tid: 69 sekunder

VĂ€rdigt, helt vĂ€rdigt. Och med tanke pĂ„ att vi under vĂ€gen lyckades lĂ€ra oss mekanismen för partitionering i PostgreSQL 10 – Ett utmĂ€rkt resultat.

En lyrisk avstickare

Kan vi göra det Ă€nnu bĂ€ttre – JA, DET KAN VI!För detta behöver vi anvĂ€nda 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 ;

Skriver om frÄgan igen:
FrÄga med anvÀndning av 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';

Och vi fÄr ytterligare en slutsats:
Det var
Kostnad: 502 997.55
Körningstid: 505 sekunder

Det blev
Kostnad: 42 481.16
Utförande tid: 43 sekunder.

Även om, sĂ„ klart, ett sĂ„ lovande resultat kan vara bedrĂ€gligt; presentationerna mĂ„ste ju uppdateras. SĂ„ det slutliga datainsamlingstiden kommer inte att hjĂ€lpa sĂ„ mycket. Men som experiment Ă€r det ganska intressant.

I sjÀlva verket, som det visade sig, tackar vi igen asmm och Habr !- frÄgan kan förbÀttras ytterligare.

Epilog

SÄ, kunden Àr nöjd. Och behöver utnyttjar situationen.

Ny uppgift: Vad kan vi komma pÄ för att fördjupa och utvidga?

Och hÀr kommer jag att tÀnka pÄ - killar, vi har ingen övervakning av vÄra PostgreSQL-databaser.

Ärligt talat, det finns viss övervakning genom Cloud Watch pĂ„ AWS. Men vilken nytta har den övervakningen för DBA? I stort sett ingen.

Om det finns en möjlighet att göra nĂ„got anvĂ€ndbart och intressant för sig sjĂ€lv, kan man inte missa en sĂ„dan chans 

EFTER SOM

Happy Party eller nÄgra rader med minnen om att lÀra sig sektionering i PostgreSQL10.

SÄ hÀr kom vi till det mest intressanta:

3:e december 2018.
Beslutet att pÄbörja arbetet med att undersöka de tillgÀngliga möjligheterna för övervakning av prestanda för PostgreSQL-frÄgor.

Men det Àr redan en helt annan historia.

FortsĂ€ttning följer


KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster