Her er en hurtig ydelsessammenligning for de forespørgsler, der er nævnt i dette indlæg.
Nuværende opsætning:
Tabellen core_message har 10.904.283 rækker, og der er 60.740 rækker i test_boats (eller 60.740 forskellige mmsi i core_message ).
Og jeg bruger PostgreSQL 11.5
Forespørgsel ved hjælp af kun indeksscanning:
1) ved at bruge DISTINCT ON :
SELECT DISTINCT ON (mmsi) mmsi
FROM core_message;
2) ved at bruge RECURSIVE med LATERAL :
WITH RECURSIVE cte AS (
(
SELECT mmsi
FROM core_message
ORDER BY mmsi
LIMIT 1
)
UNION ALL
SELECT m.*
FROM cte c
CROSS JOIN LATERAL (
SELECT mmsi
FROM core_message
WHERE mmsi > c.mmsi
ORDER BY mmsi
LIMIT 1
) m
)
TABLE cte;
3) Brug af en ekstra tabel med LATERAL :
SELECT a.mmsi
FROM test_boats a
CROSS JOIN LATERAL(
SELECT b.time
FROM core_message b
WHERE a.mmsi = b.mmsi
ORDER BY b.time DESC
LIMIT 1
) b;
Forespørgsel bruger ikke kun indeksscanning :
4) ved at bruge DISTINCT ON med mmsi,time DESC INDEX :
SELECT DISTINCT ON (mmsi) *
FROM core_message
ORDER BY mmsi, time desc;
5) ved at bruge DISTINCT ON med baglæns mmsi,time UNIQUE CONSTRAINT :
SELECT DISTINCT ON (mmsi) *
FROM core_message
ORDER BY mmsi desc, time desc;
6) ved at bruge RECURSIVE med LATERAL og mmsi,time DESC INDEX :
WITH RECURSIVE cte AS (
(
SELECT *
FROM core_message
ORDER BY mmsi , time DESC
LIMIT 1
)
UNION ALL
SELECT m.*
FROM cte c
CROSS JOIN LATERAL (
SELECT *
FROM core_message
WHERE mmsi > c.mmsi
ORDER BY mmsi , time DESC
LIMIT 1
) m
)
TABLE cte;
7) ved at bruge RECURSIVE med LATERAL og baglæns mmsi,time UNIQUE CONSTRAINT :
WITH RECURSIVE cte AS (
(
SELECT *
FROM core_message
ORDER BY mmsi DESC , time DESC
LIMIT 1
)
UNION ALL
SELECT m.*
FROM cte c
CROSS JOIN LATERAL (
SELECT *
FROM core_message
WHERE mmsi < c.mmsi
ORDER BY mmsi DESC , time DESC
LIMIT 1
) m
)
TABLE cte;
8) Brug af en ekstra tabel med LATERAL :
SELECT b.*
FROM test_boats a
CROSS JOIN LATERAL(
SELECT b.*
FROM core_message b
WHERE a.mmsi = b.mmsi
ORDER BY b.time DESC
LIMIT 1
) b;
Brug af en dedikeret tabel til den sidste besked:
9) Her er min første løsning ved at bruge en særskilt tabel med kun den sidste besked. Denne tabel udfyldes efterhånden som nye meddelelser ankommer, men kan også oprettes som sådan :
CREATE TABLE core_shipinfos AS (
WITH RECURSIVE cte AS (
(
SELECT *
FROM core_message
ORDER BY mmsi DESC , time DESC
LIMIT 1
)
UNION ALL
SELECT m.*
FROM cte c
CROSS JOIN LATERAL (
SELECT *
FROM core_message
WHERE mmsi < c.mmsi
ORDER BY mmsi DESC , time DESC
LIMIT 1
) m
)
TABLE cte);
Så er anmodningen om at få den seneste besked så simpel som den :
SELECT * FROM core_shipinfos;
Resultater:
Gennemsnit af flere forespørgsler (omkring 5 for den hurtige):
1) 9146 ms
2) 728 ms
3) 498 ms
4) 51488 ms
5) 54764 ms
6) 729 ms
7) 778 ms
8) 516 ms
9) 15 ms
Konklusion:
Jeg vil ikke kommentere på den dedikerede bordløsning og vil beholde den til sidst.
Den ekstra tabel (test_boats ) løsningen er absolut vinderen her, men den RECURSIVE løsningen er også ret effektiv.
Der er et stort hul i ydeevnen for DISTINCT ON bruger kun indeksscanning, og den der ikke bruger det, men ydeevneforøgelsen er ret lille for den anden effektive forespørgsel.
Dette giver mening, da den største forbedring, disse forespørgsler medfører, er det faktum, at de ikke behøver at gå over hele core_message tabel, men kun på en delmængde af den unikke mmsi der er væsentligt mindre (60K+) sammenlignet med core_message bordstørrelse (10M+)
Som en yderligere bemærkning, synes der ikke at være væsentlig forbedring i ydeevnen for forespørgsler, der bruger UNIQUE CONSTRAINT hvis jeg dropper mmsi,time DESC INDEX . Men at droppe det indeks vil selvfølgelig spare mig noget plads (dette indeks tager i øjeblikket 328 MB)
Om den dedikerede bordløsning:
Hver meddelelse er gemt i core_message tabel indeholder både positionsoplysninger (position, hastighed, kurs osv.) OG skibsinformationer (navn, kaldesignal, dimensioner osv.), såvel som skibsidentifikator (mmsi).
For at give lidt mere baggrund om, hvad jeg faktisk forsøger at gøre:Jeg implementerer en backend til at gemme beskeder udsendt af skibe via AIS-protokol .
Som sådan, hver unik mmsi, jeg fik, fik jeg den via denne protokol. Det er ikke en foruddefineret liste. Det bliver ved med at tilføje nyt MMSI, indtil jeg fik alle skibe i verden ved hjælp af AIS.
I den sammenhæng giver en dedikeret tabel med skibsinformationer som sidst modtaget besked mening.
Jeg kunne undgå at bruge sådan en tabel, som vi har set med RECURSIVE løsning, men... en dedikeret tabel er stadig 50 gange hurtigere end denne RECURSIVE løsning.
Den dedikerede tabel ligner faktisk test_boat tabel med flere oplysninger end blot mmsi Mark. Som det er, at have en tabel med mmsi eneste felt eller en tabel med hver sidste information om core_message tabel tilføje den samme kompleksitet til min ansøgning.
I sidste ende tror jeg, at jeg vil gå efter dette dedikerede bord. Det vil give mig uovertruffen hastighed, og jeg vil stadig have mulighed for at bruge LATERAL trick på core_message , hvilket vil give mig mere fleksibilitet.