CLUSTER
Om du tänker använda CLUSTER
, den visade syntaxen är ogiltig.
create CLUSTER ticket USING ticket_1_idx;
Kör en gång:
CLUSTER ticket USING ticket_1_idx;
Detta kan hjälpa mycket med större resultatuppsättningar. Inte så mycket för en enda rad som returneras.
Postgres kommer ihåg vilket index som ska användas för efterföljande samtal. Om din tabell inte är skrivskyddad försämras effekten med tiden och du måste köra om med vissa intervall:
CLUSTER ticket;
Möjligen bara på flyktiga partitioner. Se nedan.
Men , om du har många uppdateringar, CLUSTER
(eller VACUUM FULL
) kan faktiskt vara dåligt för prestandan. Rätt mängd uppblåsthet tillåter UPDATE
att placera nya radversioner på samma datasida och undviker behovet av att fysiskt utöka den underliggande filen i operativsystemet för ofta. Du kan använda en noggrant inställd FILLFACTOR
för att få det bästa av två världar:
- Fyllningsfaktor för ett sekventiellt index som är PK
pg_repack
CLUSTER
tar ett exklusivt lås på bordet, vilket kan vara ett problem i en miljö med flera användare. Citerar manualen:
När en tabell håller på att klustras visas en
ACCESS EXCLUSIVE
låset förvärvas på den. Detta förhindrar alla andra databasoperationer (både läser och skriver). ) från att arbeta på bordet tillsCLUSTER
är klar.
Djärv betoning min. Överväg alternativet pg_repack
:
Till skillnad från
CLUSTER
ochVACUUM FULL
det fungerar online, utan att hålla ett exklusivt lås på de behandlade tabellerna under bearbetningen. pg_repack är effektivt att starta upp, med prestanda jämförbar med att användaCLUSTER
direkt.
och:
pg_repack måste ta ett exklusivt lås i slutet av omorganisationen.
Version 1.3.1 fungerar med:
PostgreSQL 8.3, 8.4, 9.0, 9.1, 9.2, 9.3, 9.4
Version 1.4.2 fungerar med:
PostgreSQL 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 10
Fråga
Frågan är enkel nog att inte orsaka några prestandaproblem i sig.
Men ett ord om riktighet :BETWEEN
konstruktion inkluderar gränser. Din fråga väljer hela 19 december, plus poster från 20 december kl. 00:00. Det är extremt osannolikt krav. Chansen är stor att du verkligen vill:
SELECT *
FROM ticket
WHERE created >= '2012-12-19 0:0'
AND created < '2012-12-20 0:0';
Prestanda
Först och främst frågar du:
Varför väljer den sekventiell skanning?
Din EXPLAIN
utdata visar tydligt en Indexsökning , inte en sekventiell tabellskanning. Det måste finnas något slags missförstånd.
Om du pressas hårt för bättre prestanda kanske du kan förbättra saker. Men den nödvändiga bakgrundsinformationen finns inte i frågan. Möjliga alternativ inkluderar:
-
Du kan bara fråga efter obligatoriska kolumner istället för
*
för att minska överföringskostnaderna (och eventuellt andra prestationsfördelar). -
Du kan titta på partitionering och lägg praktiska tidsskivor i separata tabeller. Lägg till index till partitioner efter behov.
-
Om partitionering inte är ett alternativ skulle en annan relaterad men mindre påträngande teknik vara att lägga till ett eller flera partiella index .
Till exempel, om du mest frågar den aktuella månaden , kan du skapa följande partiella index:CREATE INDEX ticket_created_idx ON ticket(created) WHERE created >= '2012-12-01 00:00:00'::timestamp;
CREATE
ett nytt index precis före början på en ny månad. Du kan enkelt automatisera uppgiften med ett cron-jobb. ValfrittDROP
partiella index för gamla månader senare. -
Håll det totala indexet utöver det för
CLUSTER
(som inte kan fungera på partiella index). Om gamla poster aldrig ändras, skulle tabellpartitionering hjälpa den här uppgiften mycket, eftersom du bara behöver klustera nyare partitioner. Återigen om poster aldrig ändras alls, behöver du förmodligen inteCLUSTER
.
Om du kombinerar de två sista stegen bör prestanda vara fantastisk.
Grundläggande prestanda
Du kanske saknar en av grunderna. Alla vanliga prestationsråd gäller:
- https://wiki.postgresql.org/wiki/Slow_Query_Questions
- https://wiki.postgresql.org/wiki/Performance_Optimization