Het cruciale om te begrijpen is dat SQL-tabellen geen volgorde hebben . De volgorde van de rijen die u ziet wanneer u SELECT
zonder een ORDER BY
blijft alleen hetzelfde omdat het voor de database sneller is om ze in die volgorde te krijgen dan in een andere volgorde. PostgreSQL retourneert alleen rijen in deze volgorde wanneer u een sequentiële scan op de tafel uitvoert; als het een index voor de zoekopdracht kan gebruiken, krijgt u de rijen over het algemeen in een andere volgorde.
Misschien vindt u dit antwoord dat ik eerder schreef informatief.
In PostgreSQL, UPDATE
s naar rijen kunnen ze naar een andere locatie in de tabel verplaatsen, waardoor de volgorde waarin ze worden geretourneerd, wordt gewijzigd. Hetzelfde geldt voor het autovacuümproces op de achtergrond en verschillende andere bewerkingen zoals VACUUM
en CLUSTER
.
Dus je moet nooit vertrouw op de "standaard" bestelling voor alles. Als je rijen een soort volgorde wilt geven, moeten ze moeten hebben een sleutel waarop u ze kunt sorteren.
Als je een tabel zonder sleutel hebt gemaakt en je realiseert je nu dat deze er een zou moeten hebben, kun je misschien herstellen van de situatie door de ctid
te gebruiken systeem kolom. Doe niet vertrouw hierop voor productiegebruik, het is een systeeminterne kolom die alleen zichtbaar is voor gebruikers voor noodherstel en diagnostische doeleinden. Kijk eerst of de fysieke bestelling op schijf daadwerkelijk de volgorde is die u wilt:
SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;
Als dit het geval is, kunt u een nieuwe sleutelkolom toevoegen die vooraf is ingesteld op een automatisch oplopende sleutel die wordt toegepast in de rijvolgorde op de schijf. Er zijn twee manieren om dit te doen. De veiligste is:
BEGIN;
LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE;
ALTER TABLE mytable RENAME TO mytable_old;
CREATE TABLE mytable (id SERIAL PRIMARY KEY, LIKE mytable_old INCLUDING ALL);
INSERT INTO mytable
SELECT row_number() OVER () AS id, *
FROM mytable_old
ORDER BY ctid;
SELECT setval('mytable_id_seq', (SELECT max(id)+1 FROM mytable));
COMMIT;
als u zeker weet dat u tevreden bent met de resultaten, DROP TABLE mytable_old;
. Bekijk deze demo:http://sqlfiddle.com/#!12/2cb99/2
Een snelle en gemakkelijke maar minder veilige manier is om gewoon de kolom te maken en erop te vertrouwen dat PostgreSQL de tabel van begin tot eind herschrijft:
ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;
Er is absoluut geen garantie dat PostgreSQL de ID's in volgorde toewijst, hoewel dit in de praktijk wel zal gebeuren. Bekijk deze SQLFiddle-demo.
Houd er rekening mee dat wanneer u een SEQUENCE
(dat is wat een SERIAL
kolom maakt) zijn er een paar gedragingen die u misschien niet verwacht. Wanneer u meerdere rijen tegelijk invoegt, krijgen de rijen mogelijk niet noodzakelijk ID's toegewezen in de exacte volgorde die u verwacht, en ze kunnen "verschijnen" (zichtbaar worden) in een andere volgorde dan de volgorde waarin ze ID's kregen toegewezen en ingevoegd in. Als transacties worden teruggedraaid, wordt de gegenereerde ID voor altijd weggegooid, zodat u gaten in de nummering krijgt. Dit is erg goed als u wilt dat uw database snel is, maar het is niet ideaal als u nummering zonder onderbrekingen wilt. Als dat is wat je nodig hebt, zoek dan naar "postgresql gapless sequence".