Előszó vagy hogyan született a szekcionálás ötlete
A történet itt kezdődik: Miután szinte minden forrás kimerült a lekérdezés optimalizálásához, felmerült a kérdés - mi legyen tovább? Így jött a szekcionálás ötlete.

Lírai kitérő:
Pontosan 'abban az időszakban', mert . Köszönöm és a Habrnak!
Tehát, hogyan tehetjük boldogabbá az ügyfelet, miközben fejlesztjük a saját készségeinket?
Ha mindent a legegyszerűbbre leegyszerűsítünk,, akkor a drámai javítás néhány útja a adatbázis teljesítményében csupán kettő:
1) Extenzív megközelítés - erőforrások növelése, beállítások módosítása;
2) Intenzív megközelítés - lekérdezések optimalizálása
Mivel, ismétlem, abban az időszakban már nem volt világos, mit lehetne még megváltoztatni a lekérdezés gyorsításához, a megoldás az lett, hogy - táblázatok dizájnjának megváltoztatása.
Tehát - felmerül a fő kérdés - mit és hogyan fogunk megváltoztatni?
Kezdőfeltételek
Először is, egy ilyen ERD-nk van (ábrázolva önkényesen - leegyszerűsítve):

Főbb jellemzők:
- a 'sok a sokhoz' kapcsolatok
- a táblázat már potenciális szekcionálási kulccsal rendelkezik
Eredeti lekérdezés:
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' ;
A végrehajtás eredménye a tesztadatbázison:
Költség : 502 997.55
Végrehajtási idő: 505 másodperc.
Mit látunk? Egy szokásos lekérdezés, időbeli szeletekre.
Tehát végezzünk el egy egyszerű logikai következtetést: ha van egy időszakos minta, akkor segít nekünk? Helyes — a szegmentálás.
Mit szegmentáljunk?
Első pillantásra a választás egyértelmű — a "shipment" táblázat deklaratív szegmentálása a "SHIPMENT_DATE" kulcs szerint (gyorsan előreugorva — a végén a produkció kicsit más lett).
Hogyan szegmentáljunk?
Ez a kérdés sem túl nehéz. Szerencsére a PostgreSQL 10-ben most már van egy emberbarát szegmentálási mechanizmus.
Tehát:
- Mentjük az eredeti táblázat dump-ját — pg_dump source_table
- Töröljük az eredeti táblázatot — drop table source_table
- Hozzuk létre a szülő táblázatot a tartomány szerinti szegmentálással — create table source_table
- Hozzuk létre a szegmenseket — create table source_table, create index
- Importáljuk a dump-ot, amit az 1. lépésben készítettünk — pg_restore
Szegmentálási szkriptek
Az egyszerűség és kényelem kedvéért a 2., 3. és 4. lépéseket egy szkriptbe összevontuk.
Tehát:
Mentjük az eredeti táblázat dump-ját
pg_dump postgres --file=\/dump\/shipment.dmp --format=c --table=shipment --verbose > \/dump\/shipment.log 2>&1Töröljük az eredeti táblázatot + Hozzuk létre a szülő táblázatot a tartomány szerinti szegmentálással + Hozzuk létre a szegmenseket
--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
$$;Importáljuk a dump-ot
pg_restore -d postgres --data-only --format=c --table=shipment --verbose shipment.dmp > /tmp/data_dump/shipment_restore.log 2>&1Ellenőrizzük a szekcionálás eredményeit
Mit is eredményezett mindez? A végrehajtási terv teljes szövege hosszú és unalmas, így nyugodtan lehet az összegző számokra korlátozódni.
Volt
Költség: 502 997.55
Végrehajtási idő: 505 másodperc.
Lett
Költség: 77 872.36
Végrehajtási idő: 79 másodperc.
Teljesen jó eredmény. Csökkentettük a költségeket és a végrehajtási időt. Így a particionálás használata hozza a várt hatást, összességében meglepetések nélkül.
Megörvendeztetni az ügyfelet
A tesztelési eredményeket az ügyfél számára bemutatták. A megismerés után kicsit váratlan ítéletet hozott: „Remek, particionálja a 'data' táblát.”
Igen, de mi egészen másik táblát, a 'shipment' táblát vizsgáltuk, a 'data' táblának nincsen 'SHIPMENT_DATE' mezője.
Nem probléma, adjon hozzá, változtasson. A lényeg, hogy az ügyfél elégedett legyen a végeredménnyel, a megvalósítás részletei nem annyira fontosak.
Particionáljuk az alap 'data' táblát
Alapvetően különösebb nehézségek nem merültek fel. Bár a particionálási algoritmus természetesen kissé megváltozott.
Hozzáadjuk a 'SHIPMENT_DATE' oszlopot a 'data' táblához
psql -h host -U database -d user
=> ALTER TABLE data ADD COLUMN "SHIPMENT_DATE" timestamp without time zone ;Kitöltjük a 'SHIPMENT_DATE' oszlop értékeit a 'data' táblában az azonos nevű oszlop értékeivel a 'shipment' táblából
-----------------------------
--update_data.sql
--frissítés a módosított 'data' táblához a 'shipment' táblából a 'shipment_data' értékeivel
--verzió 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 'Összesen %',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 'sor szám = % , összesen %',row_count,total_rows;
END LOOP;
end
$$;Mentjük a 'data' tábla dump-ját
pg_dump postgres --file=\/dump\/data.dmp --format=c --table=data --verbose > \/dump\/data.log 2>&1<\/sourceÚjra létrehozzuk a particionált 'data' táblát
--create_partition_data.sql
--partíciók létrehozása a "wafer data" táblához a "shipment_data" időszakos oszlop alapján, egy hónapos időtartammal
--verzió 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 'IDEIGLENES TÁBLA LÉTREHOZÁSA A SZÁLLÍTÁSI DÁTUMHOZ';
CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;
RAISE NOTICE 'ADAT TÁBLA TÖRLÉSE';
drop table data cascade ;
RAISE NOTICE 'PARTÍCIONÁLT ADAT TÁBLA LÉTREHOZÁSA';
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 'PARTÍCIONÁK LÉTREHOZÁSA A DATA TÁBLÁHOZ';
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") ;
--Határok inicializálása
IF begin_year = '0' THEN
RAISE NOTICE '***Határok inicializálása';
first_flag := true ; --első alkalom jelző
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;
-- Ellenőrizze az aktuális dátumot a határok között NEM az első alkalomra
RAISE NOTICE 'Aktuális adat = %',to_char( to_date( current_year||'.'||current_month, 'YYYY.MM'), 'YYYY.MM');
RAISE NOTICE 'Kezdő adat = %',to_char( to_date( begin_year||'.'||begin_month, 'YYYY.MM'), 'YYYY.MM');
RAISE NOTICE 'Következő adat = %',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 '***FOLYTATÁS';
CONTINUE ;
ELSE
--Új határok csak másodszor és az után
RAISE NOTICE '***ÚJ HATÁROK';
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 'PARTÍCIÓ SZÁMA % , TÁBLA NEVE =%',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 NÉV =%',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 NÉV =%',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 NÉV =%',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 NÉV =%',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 NÉV =%',index_name;
EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ;
--Törölje az első alkalom jelzőt
first_flag := false ;
END LOOP;
end
$$;
Betöltjük a 3. lépésben létrehozott dump fájlt.
pg_restore -h host -u felhasználó -d adatbázis --data-only --format=c --table=data --verbose data.dmp > data_restore.log 2>&1Külön szekciót hozunk létre a régi adatok számára
---------------------------------------------------
--create_partition_for_old_dates.sql
--partíciók létrehozása a régi dátumok tárolásához
--verzió 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 'Régi dátum: %', rec_shipment_date.min_date ;
partition_name := 'data_old_dates' ;
RAISE NOTICE 'PARTÍCÓ NEVE: %', 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
$$;Végeredmények:
Volt
Költség: 502 997.55
Végrehajtási idő: 505 másodperc.
Lett
Költség: 68 533.70
Végrehajtási idő: 69 másodperc
Megfelelő, igazán megfelelő. Figyelembe véve, hogy útközben sikerült viszonylag elsajátítani a PostgreSQL 10 szekcionáló mechanizmusát - Kiváló eredmény.
Lírai kitérő
Lehetne még jobb - IGEN, LEHETSÉGES!Ehhez MATERIALIZED VIEW-t kell használni.
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 ;
Ismét átfogalmazzuk a lekérdezést:
Lekérdezés materialized view használatával
VÁLASZ
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';
És kapunk egy újabb eredményt:
Volt
Költség: 502 997.55
Végrehajtási idő: 505 másodperc
Lett
Költség: 42 481.16
Végrehajtási idő: 43 másodperc.
Bár nyilvánvalóan, egy ilyen ígéretes eredmény megtévesztő lehet, a megjelenéseket frissíteni kell. Tehát az adatok megszerzésének végső ideje nem sokat fog segíteni. De kísérletként mindenképpen érdekes.
Valójában, ahogy kiderült, még egyszer köszönöm és a Habrunak !-
Utószó
Tehát az ügyfél elégedett. És a készülék helyének ismeretére. Ha kihasználni a helyzetet.
Új feladat: Mit lehetne kitalálni, hogy mélyebb és szélesebb legyen?
És itt jut eszünkbe — srácok, de hiszen nincs monitorozásunk a PostgreSQL adatbázisainkról.
A szívünkre tesszük a kezünket, van valamiféle monitorozás a Cloud Watch-on az AWS-en. De mi haszna van ebből a monitorozásból a DBA számára? Valójában szinte semmi.
Ha lehetőség nyílt egy hasznos és érdekes dolog létrehozására magunk számára, nem lehet elhagyni egy ilyen esélyt ...
MERT

Így jutottunk el a legérdekesebbhez:
2018. december 3.
Döntés a PostgreSQL lekérdezések teljesítményének monitorozásának lehetőségeinek kutatásáról.
De ez már egy teljesen másik történet.
Folytatás következik…
Forrás: habr.com
