To ting:1) du bruger ikke databasen i dets fulde omfang, og 2) dit problem er et godt eksempel på en tilpasset PostgreSQL-udvidelse. Her er hvorfor.
Du bruger kun databasen som lagring og gemmer farver som flydere. I din nuværende konfiguration vil databasen, uanset forespørgselstype, altid skulle kontrollere alle værdier (foretag en sekventiel scanning). Dette betyder en masse IO og en masse beregning for få returnerede kampe. Du forsøger at finde de nærmeste N farver, så der er et par muligheder for, hvordan du undgår at udføre beregninger på alle data.
Simpel forbedring
Det enkleste er at begrænse dine beregninger til en mindre delmængde af data. Du kan antage, at forskellen vil være større, hvis komponenterne adskiller sig mere. Hvis du kan finde en sikker forskel mellem komponenterne, hvor resultaterne altid er upassende, kan du helt udelukke disse farver ved at bruge ranged WHERE med btree-indekser. Men på grund af karakteren af L*a*b farverum, vil dette sandsynligvis forværre dine resultater.
Opret først indekserne:
OPRET INDEKS color_lab_l_btree PÅ farve VED HJÆLP AF btree (lab_l);OPRET INDEX color_lab_a_btree ON color VED HJÆLP af btree (lab_a);OPRET INDEKS color_lab_b_btree PÅ farve BRUGE btree (lab_b);
Derefter tilpassede jeg din forespørgsel til at inkludere en WHERE-klausul til kun at filtrere farver, hvor nogen af komponenterne afviger i højst 20.
Opdatering: Efter endnu et kig vil tilføjelse af en grænse på 20 højst sandsynligt forværre resultaterne, da jeg fandt mindst ét punkt i rummet, hvilket dette gælder for.:
VÆLG c.rgb_r, c.rgb_g, c.rgb_b, DELTA_E_CIE2000( 25.805780252087963, 53.33446637366859, -45.03961_4537, c.03.00, c.01, c.01, c.01, c.01, c.01, c.01, c.01. Hvor c.lab_l mellem 25.805780252087963 - 20 og 25.805780252087963 + 20 og C.LAB_A mellem 53.33446637366859 - 20 og 53.33446637366859 + 20 og C.LAB_B mellem -45.0396135373749440
Jeg fyldte tabellen med 100.000 tilfældige farver med dit script og testede:
Tid uden indeks:44006,851 ms
Tid med indekser og intervalforespørgsel:1293.092 ms
Du kan tilføje denne WHERE-sætning til delta_e_cie1976_query
på mine tilfældige data falder det også forespørgselstiden fra ~110 ms til ~22 ms.
BTW:Jeg fik tallet 20 empirisk:Jeg prøvede med 10, men fik kun 380 poster, hvilket virker lidt lavt og måske udelukker nogle bedre muligheder, da grænsen er 100. Med 20 var det fulde sæt 2900 rækker, og man kan være nogenlunde sikker på, at de nærmeste kampe vil være der. Jeg studerede ikke DELTA_E_CIE2000 eller L*a*b* farverum i detaljer, så tærsklen skal muligvis justeres langs forskellige komponenter for at det faktisk er sandt, men princippet om at ekskludere ikke-interessante data gælder.
Omskriv Delta E CIE 2000 i C
Som du allerede har sagt, er Delta E CIE 2000 kompleks og ret uegnet til implementering i SQL. Den bruger i øjeblikket omkring 0,4 ms pr. opkald på min bærbare computer. Implementering af det i C skulle fremskynde dette betydeligt. PostgreSQL tildeler standardomkostninger til SQL-funktioner som 100 og C-funktioner som 1. Jeg gætter på, at dette er baseret på reel erfaring.
Opdatering: Da dette også ridser en af mine kløer, genimplementerede jeg Delta E-funktionerne fra colormath-modulet i C som en PostgreSQL-udvidelse, tilgængelig på PGXN
. Med dette kan jeg se en speedup på omkring 150x for CIE2000, når jeg forespørger alle posterne fra tabellen med 100.000 poster.
Med denne C-funktion får jeg forespørgselstider mellem 147 ms og 160 ms for 100k farver. Med ekstra WHERE er forespørgselstiden omkring 20 ms, hvilket virker ganske acceptabelt for mig.
Bedste, men avancerede løsning
Men da dit problem er N nærmeste nabosøgning i 3-dimensionelt rum, kan du bruge K-Nearest-Neighbor Indexing, som er i PostgreSQL siden version 9.1
.
For at det skal virke, skal du sætte L*a*b*-komponenter i en terning
. Denne udvidelse understøtter endnu ikke distanceoperatør ( det er undervejs
), men selvom det ville, ville det ikke understøtte Delta E-afstande, og du skulle genimplementere det som en C-udvidelse.
Dette betyder implementering af GiST-indeksoperatørklasse (btree_gist PostgreSQL-udvidelse
i bidrag gør dette) for at understøtte indeksering i henhold til Delta E-afstande. Det gode er, at du så kan bruge forskellige operatører til forskellige versioner af Delta E, f.eks. <-> til Delta E CIE 2000 og <#>
for Delta E CIE 1976 og forespørgsler ville være virkelig rigtig hurtige
for lille LIMIT selv med Delta E CIE 2000.
I sidste ende kan det afhænge af, hvad dine (forretnings)krav og begrænsninger er.