sql >> Databasteknik >  >> RDS >> PostgreSQL

En guide till partitionering av data i PostgreSQL

Vad är datapartitionering?

För databaser med extremt stora tabeller är partitionering ett underbart och listigt knep för databasdesigners för att förbättra databasprestanda och göra underhållet mycket enklare. Den maximala tabellstorleken som tillåts i en PostgreSQL-databas är 32 TB, men om den inte körs på en dator som ännu inte har uppfunnits i framtiden, kan prestandaproblem uppstå på en tabell med bara en hundradel av det utrymmet.

Partitionering delar upp en tabell i flera tabeller och görs i allmänhet på ett sätt så att applikationer som kommer åt tabellen inte märker någon skillnad, annat än att de är snabbare att komma åt de data som den behöver. Genom att dela upp tabellen i flera tabeller är tanken att tillåta exekveringen av frågorna att behöva skanna mycket mindre tabeller och index för att hitta den data som behövs. Oavsett hur effektiv en indexstrategi är, kommer det alltid att gå mycket snabbare att skanna ett index för en tabell som är 50GB än ett index som är för en tabell på 500GB. Detta gäller även för tabellskanningar, för ibland är tabellgenomsökningar helt enkelt oundvikliga.

När du introducerar en partitionerad tabell till frågeplaneraren finns det några saker att veta och förstå om själva frågeplaneraren. Innan en fråga faktiskt körs, kommer frågeplaneraren att ta frågan och planera det mest effektiva sättet att komma åt data. Genom att ha informationen uppdelad på olika tabeller kan planeraren bestämma vilka tabeller som ska komma åt och vilka tabeller som ska ignoreras helt, baserat på vad varje tabell innehåller.

Detta görs genom att lägga till begränsningar för de uppdelade tabellerna som definierar vilken data som är tillåten i varje tabell, och med en bra design kan vi låta frågeplaneraren skanna en liten delmängd av data snarare än hela grejen.

Bör en tabell delas upp?

Partitionering kan drastiskt förbättra prestanda på ett bord när det görs på rätt sätt, men om det görs fel eller när det inte behövs kan det göra prestandan sämre, till och med oanvändbar.

Hur stort är bordet?

Det finns ingen riktig regel för hur stor en tabell måste vara innan partitionering är ett alternativ, men baserat på databasåtkomsttrender kommer databasanvändare och administratörer att börja se prestanda på en specifik tabell börja försämras när den blir större. I allmänhet bör partitionering endast övervägas när någon säger "Jag kan inte göra X eftersom bordet är för stort." För vissa värdar kan 200 GB vara rätt tidpunkt att partitionera, för andra kan det vara dags att partitionera när den når 1 TB.

Om tabellen är fast besluten att vara "för stor", är det dags att titta på åtkomstmönstren. Antingen genom att känna till applikationerna som har åtkomst till databasen, eller genom att övervaka loggar och generera frågerapporter med något som pgBadger, kan vi se hur en tabell nås, och beroende på hur den nås kan vi ha alternativ för en bra partitioneringsstrategi.

För att lära dig mer om pgBadger och hur du använder det, läs vår tidigare artikel om pgBadger.

Är tabelluppblåsthet ett problem?

Uppdaterade och raderade rader resulterar i döda tuplar som i slutändan måste rensas upp. Dammsugningstabeller, antingen manuellt eller automatiskt, går över varje rad i tabellen och avgör om den ska återvinnas eller lämnas ifred. Ju större tabellen är, desto längre tid tar denna process och desto mer systemresurser används. Även om 90 % av en tabell är oföränderlig data, måste den skannas varje gång ett vakuum körs. Att partitionera tabellen kan hjälpa till att minska tabellen som behöver dammsugas till mindre, minska mängden oföränderlig data som behöver skannas, mindre tid att dammsuga totalt och mer systemresurser frigörs för användaråtkomst snarare än systemunderhåll.

Hur raderas data, om alls?

Om data raderas enligt ett schema, säg att data som är äldre än 4 år raderas och arkiveras, kan detta resultera i kraftiga delete-satser som kan ta tid att köra, och som tidigare nämnt, skapa döda rader som behöver dammsugas. Om en bra partitioneringsstrategi implementeras, kan en flera timmar lång DELETE-sats med dammsugningsunderhåll efteråt förvandlas till en en minuts DROP TABLE-sats på en gammal månadstabell utan vakuumunderhåll.

Hur bör tabellen delas upp?

Nycklarna för åtkomstmönster finns i WHERE-satsen och JOIN-villkoren. Varje gång en fråga anger kolumner i WHERE- och JOIN-klausulerna, säger den till databasen "detta är data jag vill ha". Precis som att designa index som riktar in sig på dessa satser, förlitar sig partitioneringsstrategier på att rikta in sig på dessa kolumner för att separera data och ha åtkomst till frågan så få partitioner som möjligt.

Exempel:

  1. En transaktionstabell med en datumkolumn som alltid används i en where-sats.
  2. En kundtabell med platskolumner, till exempel bosättningsland som alltid används i where-klausuler.

De vanligaste kolumnerna att fokusera på för partitionering är vanligtvis tidsstämplar, eftersom vanligtvis en stor del av data är historisk information och sannolikt kommer att ha en ganska förutsägbar data spridd över olika tidsgrupper.

Fastställ dataspridningen

När vi har identifierat vilka kolumner vi ska partitionera på bör vi ta en titt på spridningen av data, med målet att skapa partitionsstorlekar som sprider data så jämnt som möjligt över de olika underordnade partitionerna.

severalnines=# SELECT DATE_TRUNC('year', view_date)::DATE, COUNT(*) FROM website_views GROUP BY 1 ORDER BY 1;
 date_trunc |  count
------------+----------
 2013-01-01 | 11625147
 2014-01-01 | 20819125
 2015-01-01 | 20277739
 2016-01-01 | 20584545
 2017-01-01 | 20777354
 2018-01-01 |   491002
(6 rows)

I det här exemplet trunkerar vi tidsstämpelkolumnen till en årstabell, vilket resulterar i cirka 20 miljoner rader per år. Om alla våra frågor anger ett eller flera datum, eller datumintervall, och de angivna vanligtvis täcker data inom ett enda år, kan detta vara en bra startstrategi för partitionering, eftersom det skulle resultera i en enda tabell per år , med ett hanterbart antal rader per tabell.

Ladda ner Whitepaper Today PostgreSQL Management &Automation med ClusterControlLäs om vad du behöver veta för att distribuera, övervaka, hantera och skala PostgreSQLDladda Whitepaper

Skapa en partitionerad tabell

Det finns ett par sätt att skapa partitionerade tabeller, men vi kommer främst att fokusera på den mest funktionsrika typen tillgängliga, triggerbaserad partitionering. Detta kräver manuell installation och lite kodning i plpgsql-procedurspråket för att komma igång.

Den fungerar genom att ha en överordnad tabell som i slutändan kommer att bli tom (eller förbli tom om det är en ny tabell), och underordnade tabeller som ÄRVER den överordnade tabellen. När den överordnade tabellen efterfrågas, söks även de underordnade tabellerna efter data på grund av den INHERIT som tillämpas på de underordnade tabellerna. Men eftersom underordnade tabeller endast innehåller delmängder av förälderns data, lägger vi till en BEGRÄNSNING på tabellen som gör en KONTROLL och verifierar att data stämmer överens med vad som är tillåtet i tabellen. Detta gör två saker:För det första vägrar den data som inte hör hemma, och för det andra talar den om för frågeplaneraren att endast data som matchar denna KONTROLLBESKRIVNING är tillåtna i den här tabellen, så om du söker efter data som inte matchar tabellen, inte ens bry dig om att söka efter det.

Slutligen tillämpar vi en utlösare på den överordnade tabellen som exekverar en lagrad procedur som bestämmer vilken underordnad tabell som ska läggas in data.

Skapa tabell

Att skapa den överordnade tabellen är som vilken annan tabell som helst.

severalnines=# CREATE TABLE data_log (data_log_sid SERIAL PRIMARY KEY,
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR);
CREATE TABLE

Skapa underordnade tabeller

Att skapa underordnade tabeller är liknande, men innebär några tillägg. För organisatorisk skull kommer vi att ha våra underordnade tabeller i ett separat schema. Gör detta för varje underordnad tabell, ändra detaljerna därefter.

OBS:Namnet på sekvensen som används i nextval() kommer från sekvensen som föräldern skapade. Detta är avgörande för att alla underordnade tabeller ska använda samma sekvens.

severalnines=# CREATE SCHEMA part;
CREATE SCHEMA

severalnines=# CREATE TABLE part.data_log_2018 (data_log_sid integer DEFAULT nextval('public.data_log_data_log_sid_seq'::regclass),
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR)
 INHERITS (public.data_log);
CREATE TABLE

severalnines=# ALTER TABLE ONLY part.data_log_2018
    ADD CONSTRAINT data_log_2018_pkey PRIMARY KEY (data_log_sid);
ALTER TABLE

severalnines=# ALTER TABLE part.data_log_2018 ADD CONSTRAINT data_log_2018_date CHECK (date >= '2018-01-01' AND date < '2019-01-01');
ALTER TABLE

Skapa funktion och utlösare

Slutligen skapar vi vår lagrade procedur och lägger till triggern i vår överordnade tabell.

severalnines=# CREATE OR REPLACE FUNCTION 
 public.insert_trigger_table()
  RETURNS trigger
  LANGUAGE plpgsql
 AS $function$
 BEGIN
     IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
         INSERT INTO part.data_log_2018 VALUES (NEW.*);
         RETURN NULL;
     ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
         INSERT INTO part.data_log_2019 VALUES (NEW.*);
         RETURN NULL;
     END IF;
 END;
 $function$;
CREATE FUNCTION

severalnines=# CREATE TRIGGER insert_trigger BEFORE INSERT ON data_log FOR EACH ROW EXECUTE PROCEDURE insert_trigger_table();
CREATE TRIGGER

Testa det

Nu när allt är skapat, låt oss testa det. I det här testet har jag lagt till fler årliga tabeller som täcker 2013 - 2020.

Obs:Infogningssvaret nedan är "INSERT 0 0", vilket skulle tyda på att det inte infogade något. Detta kommer att behandlas senare i den här artikeln.

severalnines=# INSERT INTO data_log (date, event_details) VALUES ('2018-08-20 15:22:14', 'First insert');
INSERT 0 0

severalnines=# SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |            date            | event_details
--------------+----------------------------+---------------
            1 | 2018-08-17 23:01:38.324056 | First insert
(1 row)

Det finns, men låt oss titta på frågeplaneraren för att se till att raden kom från rätt underordnad tabell och att den överordnade tabellen inte returnerade några rader alls.

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log;
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..130.12 rows=5813 width=44) (actual time=0.016..0.019 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
   ->  Seq Scan on data_log_2015  (cost=0.00..21.30 rows=1130 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2013  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2014  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2016  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2017  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2018  (cost=0.00..1.02 rows=2 width=44) (actual time=0.005..0.005 rows=1 loops=1)
   ->  Seq Scan on data_log_2019  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2020  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
 Planning time: 0.373 ms
 Execution time: 0.069 ms
(12 rows)

Goda nyheter, den enda raden vi infogade hamnade i 2018 års tabell, där den hör hemma. Men som vi kan se specificerar frågan inte en where-sats med hjälp av datumkolumnen, så för att hämta allt gjorde frågeplaneraren och exekveringen en sekventiell skanning på varje enskild tabell.

Låt oss sedan testa med en where-klausul.

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.013..0.014 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.006 rows=1 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.591 ms
 Execution time: 0.041 ms
(7 rows)

Här kan vi se att frågeplaneraren och exekveringen gjorde en sekventiell skanning av två tabeller, den överordnade och den underordnade tabellen för 2018. Det finns underordnade tabeller för åren 2013 - 2020, men de andra än 2018 fick aldrig åtkomst eftersom where-satsen har ett intervall som bara hör till 2018. Frågeplaneraren uteslöt alla andra tabeller eftersom CHECK CONSTRAINT anser att det är omöjligt att data finns i dessa tabeller.

Arbetspartitioner med strikta ORM-verktyg eller infogade radvalidering

Som nämnts tidigare returnerar exemplet vi byggde en 'INSERT 0 0' även om vi infogade en rad. Om de program som infogar data i dessa partitionerade tabeller förlitar sig på att verifiera att raderna som infogas är korrekta, kommer dessa att misslyckas. Det finns en fix, men den lägger till ytterligare ett lager av komplexitet till den partitionerade tabellen, så den kan ignoreras om det här scenariot inte är ett problem för de program som använder den partitionerade tabellen.

Använda en vy istället för den överordnade tabellen.

Lösningen för det här problemet är att skapa en vy som frågar den överordnade tabellen och dirigera INSERT-satser till vyn. Att infoga i en vy kan låta galet, men det är där triggern på vyn kommer in.

severalnines=# CREATE VIEW data_log_view AS 
 SELECT data_log.data_log_sid,
     data_log.date,
     data_log.event_details
    FROM data_log;
CREATE VIEW

severalnines=# ALTER VIEW data_log_view ALTER COLUMN data_log_sid SET default nextval('data_log_data_log_sid_seq'::regclass);
ALTER VIEW

Att fråga den här vyn kommer att se ut precis som att fråga huvudtabellen, och WHERE-satser samt JOINS kommer att fungera som förväntat.

Visa specifik funktion och utlösare

Istället för att använda funktionen och triggern vi definierade tidigare, kommer de båda att vara något annorlunda. Ändringar i fetstil.

CREATE OR REPLACE FUNCTION public.insert_trigger_view()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
    IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
        INSERT INTO part.data_log_2018 VALUES (NEW.*);
        RETURN NEW;

    ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
        INSERT INTO part.data_log_2019 VALUES (NEW.*);
        RETURN NEW;

    END IF;
END;
$function$;

severalnines=# CREATE TRIGGER insert_trigger INSTEAD OF INSERT ON data_log_view FOR EACH ROW EXECUTE PROCEDURE insert_trigger_view();

Definitionen "INSTEAD OF" tar över kommandot infoga på vyn (vilket inte skulle fungera ändå) och kör funktionen istället. Funktionen vi definierade har ett mycket specifikt krav på att göra en "RETURN NEW;" efter att infogningen i de underordnade tabellerna är klar. Utan detta (eller att göra det som vi gjorde tidigare med 'RETURN NULL') kommer att resultera i 'INSERT 0 0' istället för 'INSERT 0 1' som vi skulle förvänta oss.

Exempel:

severalnines=# INSERT INTO data_log_view (date, event_details) VALUES ('2018-08-20 18:12:48', 'First insert on the view');
INSERT 0 1

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.015..0.017 rows=2 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.009..0.009 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.007 rows=2 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.633 ms
 Execution time: 0.048 ms
(7 rows)

severalnines=# SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |        date         |      event_details
--------------+---------------------+--------------------------
            1 | 2018-08-20 15:22:14 | First insert
            2 | 2018-08-20 18:12:48 | First insert on the view
(2 rows)

Applikationer som testar för att det infogade "rowcount" är korrekt kommer att finna att denna korrigering fungerar som förväntat. I det här exemplet har vi lagt till _view till vår vy och lagrade procedur, men om tabellen är att önska att den ska partitioneras utan att någon användare vet / applikationsändring, då skulle vi byta namn på den överordnade tabellen till data_log_parent, och anropa vyn av den gamla överordnade tabellens namn.

Uppdatera en rad och ändra det partitionerade kolumnvärdet

En sak att vara medveten om är att om du utför en uppdatering av data i den partitionerade tabellen och ändrar värdet på kolumnen till något som inte tillåts av begränsningen kommer det att resultera i ett fel. Om den här typen av uppdatering aldrig kommer att ske kan den ignoreras, men om det är en möjlighet bör en ny trigger för UPPDATERINGSprocesser skrivas som effektivt tar bort raden från den gamla underordnade partitionen och infogar en ny i ny underordnad målpartition.

Skapa framtida partitioner

Att skapa framtida partitioner kan göras på några olika sätt, var och en med sina för- och nackdelar.

Framtida partitionsskapare

Ett externt program kan skrivas upp för att skapa framtida partitioner X gånger innan de behövs. I ett partitioneringsexempel partitionerat på ett datum kan nästa partition som behövs för att skapa (i vårt fall 2019) ställas in att skapas någon gång i december. Detta kan vara ett manuellt skript som körs av databasadministratören, eller inställt på att cron ska köra det vid behov. Årliga partitioner skulle innebära att den körs en gång om året, men dagliga partitioner är vanliga, och ett dagligt cron-jobb ger en lyckligare DBA.

Automatisk partitionsskapare

Med kraften i plpgsql kan vi fånga fel om vi försöker infoga data i en underordnad partition som inte finns, och i farten skapa den nödvändiga partitionen och sedan försöka infoga igen. Det här alternativet fungerar bra förutom i de fall där många olika klienter infogar liknande data samtidigt, kan orsaka ett race-tillstånd där en klient skapar tabellen, medan en annan försöker skapa samma tabell och får ett fel om att den redan existerar. Smart och avancerad plpgsql-programmering kan fixa detta, men om det är värt ansträngningsnivån eller inte är upp till diskussion. Om detta tävlingstillstånd inte kommer att hända på grund av insticksmönstren, så finns det inget att oroa sig för.

Släpp partitioner

Om regler för datalagring dikterar att data raderas efter en viss tid, blir detta lättare med partitionerade tabeller om de partitioneras på en datumkolumn. Om vi ​​ska radera data som är 10 år gamla kan det vara så enkelt som:

severalnines=# DROP TABLE part.data_log_2007;
DROP TABLE

Detta är mycket snabbare och mer effektivt än ett "DELETE"-uttalande, eftersom det inte resulterar i några döda tuplar att städa upp med ett vakuum.

Obs:Om du tar bort tabeller från partitionsinställningarna, bör koden i triggerfunktionerna också ändras så att det inte leder datumet till den släppta tabellen.

Saker att veta innan du partitionerar

Partitioneringstabeller kan erbjuda en drastisk förbättring av prestanda, men det kan också göra det värre. Innan du går till produktionsservrar bör partitioneringsstrategin testas utförligt, för datakonsistens, prestandahastighet, allt. Att partitionera ett bord har några rörliga delar, de bör alla testas för att säkerställa att det inte finns några problem.

När det gäller att bestämma antalet partitioner, rekommenderas det starkt att hålla antalet underordnade tabeller under 1000 tabeller, och ännu lägre om möjligt. När antalet underordnade tabeller kommer över ~1000, börjar prestandan ta ett dyk eftersom frågeplaneraren i slutändan tar mycket längre tid bara att göra frågeplanen. Det är inte ovanligt att en frågeplan tar många sekunder, medan den faktiska exekveringen bara tar några millisekunder. Om tusentals förfrågningar betjänas per minut, kan flera sekunder få applikationer att stanna.

De lagrade procedurerna för plpgsql-utlösaren kan också bli komplicerade, och om de är för komplicerade kan de också sakta ner prestandan. Den lagrade proceduren exekveras en gång för varje rad som infogas i tabellen. Om det slutar med att det gör för mycket bearbetning för varje rad, kan skären bli för långsamma. Prestandatestning kommer att se till att det fortfarande är inom acceptabelt intervall.

Var kreativ

Partitioneringstabeller i PostgreSQL kan vara så avancerade som behövs. Istället för datumkolumner kan tabeller delas upp i en kolumn "land", med en tabell för varje land. Partitionering kan göras på flera kolumner, som både en kolumn "datum" och en "land". Detta kommer att göra den lagrade proceduren som hanterar skären mer komplex, men det är 100 % möjligt.

Kom ihåg att målen med partitionering är att bryta ner extremt stora tabeller i mindre, och göra det på ett genomtänkt sätt för att tillåta frågeplaneraren att komma åt data snabbare än den kunde ha i den större ursprungliga tabellen.

Deklarativ partitionering

I PostgreSQL 10 och senare introducerades en ny partitioneringsfunktion "Deklarativ partitionering". Det är ett enklare sätt att ställa in partitioner, men det har vissa begränsningar. Om begränsningarna är acceptabla kommer det sannolikt att fungera snabbare än den manuella partitionsinställningen, men stora mängder testning kommer att verifiera det.

Den officiella postgresql-dokumentationen har information om deklarativ partitionering och hur det fungerar. Det är nytt i PostgreSQL 10, och med version 11 av PostgreSQL vid horisonten när detta skrivs, är några av begränsningarna fixade, men inte alla. När PostgreSQL utvecklas kan deklarativ partitionering bli en fullständig ersättning för den mer komplexa partitioneringen som behandlas i den här artikeln. Tills dess kan deklarativ partitionering vara ett enklare alternativ om ingen av begränsningarna begränsar partitioneringsbehoven.

Deklarativa partitioneringsbegränsningar

PostgreSQL-dokumentationen tar upp alla begränsningarna med denna typ av partitionering i PostgreSQL 10, men en bra översikt finns på The Official PostgreSQL Wiki som listar begränsningarna i ett lättare att läsa format, samt noterar vilka som har fixats i den kommande PostgreSQL 11.

Fråga gruppen

Databasadministratörer över hela världen har designat avancerade och anpassade partitioneringsstrategier under lång tid, och många av oss umgås i IRC och e-postlistor. Om hjälp behövs för att bestämma den bästa strategin, eller bara få en bugg i en lagrad procedur löst, är communityn här för att hjälpa.

  • IRC
    Freenode har en mycket aktiv kanal som heter #postgres, där användare hjälper varandra att förstå koncept, fixa fel eller hitta andra resurser.
  • E-postlistor
    PostgreSQL har en handfull e-postlistor som kan anslutas. Längre frågor/ärenden kan skickas hit och kan nå många fler än IRC vid varje given tidpunkt. Listorna kan hittas på PostgreSQL-webbplatsen, och listorna pgsql-general eller pgsql-admin är bra resurser.

  1. Användardefinierad rutin med DBMS_STATS, del II

  2. Uppgradering till PostgreSQL 11 med logisk replikering

  3. Hur skapar man en slumpmässig sträng som är lämplig för ett sessions-ID i PostgreSQL?

  4. 4 datatyper som ska fasas ut i SQL Server