sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur håller data inte sorteras?

Det avgörande att förstå är att SQL-tabeller inte har en ordning . Ordningen på raderna du ser när du SELECT utan en ORDER BY förblir bara detsamma eftersom det är snabbare för databasen att få dem i den ordningen än någon annan ordning. PostgreSQL kommer bara att returnera rader i denna ordning när du gör en sekventiell skanning på tabellen; om den kan använda ett index för frågan kommer du vanligtvis att få raderna i någon annan ordning.

Du kanske tycker att det här svaret jag skrev tidigare är informativt.

I PostgreSQL, UPDATE s till rader kan flytta dem till en annan plats i tabellen, ändra ordningen de returneras i. Det kan även bakgrundsprocessen för autovakuum och olika andra operationer som VACUUM och CLUSTER .

Så du får aldrig lita på "standard"-beställningen för vad som helst. Om du vill ge rader någon form av ordning, måste de har en nyckel som du kan sortera dem på.

Om du har skapat en tabell utan nyckel och nu inser att den borde ha en, kanske du kan återhämta dig från situationen genom att använda ctid systemkolumn. Gör inte lita på detta för produktionsanvändning, det är en systemintern kolumn som endast är synlig för användare för nödåterställning och diagnostik. Se först om den fysiska beställningen på disken verkligen är den ordning du vill ha:

SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;

Om så är fallet kan du lägga till en ny nyckelkolumn som är förinställd på en automatiskt inkrementerad nyckel som tillämpas i radordningen på disken. Det finns två sätt att göra detta. Det säkraste är:

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;

När du sedan är säker på att du är nöjd med resultaten, DROP TABLE mytable_old; . Se denna demo:http://sqlfiddle.com/#!12/2cb99/2

Ett snabbt och enkelt men mindre säkert sätt är att bara skapa kolumnen och lita på att PostgreSQL skriver om tabellen från början till slut:

ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;

Det finns absolut ingen garanti att PostgreSQL kommer att tilldela ID:n i ordning, även om det i praktiken kommer att göra det. Se den här SQLFiddle-demon.

Tänk på att när du använder en SEQUENCE (vilket är vad en SERIAL kolumnen skapar) finns det några beteenden du kanske inte förväntar dig. När du infogar flera rader samtidigt, kanske raderna inte nödvändigtvis får tilldelade ID:n i exakt den ordning du förväntar dig att de ska, och de kan "visas" (bli synliga) i en annan ordning än den ordning de tilldelades ID:n och infogades Dessutom, om transaktioner rullar tillbaka, slängs det genererade ID:t för alltid, så du får luckor i numreringen. Detta är mycket bra om du vill att din databas ska vara snabb, men det är inte idealiskt om du vill ha numrering utan mellanrum. Om det är vad du behöver, sök efter "postgresql gapless sequence".



  1. PostgreSQL - Lägg till nyckel till varje objekt i en JSONB-array

  2. Fel:INSERT EXEC-satsen kan inte kapslas. och Kan inte använda ROLLBACK-satsen i en INSERT-EXEC-sats. Hur löser man detta?

  3. Hur man visar rader som inte finns i en annan tabell i MySQL

  4. TOP 5 MySQL Ta bort syntax med tips för T-SQL-utvecklare