Kom ihåg mig?
Home Menu

Menu


Prestandaproblem med komplicerad SQL och 400.000 rader

 
 
Ämnesverktyg Visningsalternativ
Oläst 2011-11-30, 21:35 #1
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
Standard Prestandaproblem med komplicerad SQL och 400.000 rader

Nu fick jag en svårare nöt att knäcka. Jag har en tabell som innehåller ca 400.000 rader och alla (nästan) har en latitud/longitud koordinat. Jag vill då skriva frågor som innebär att lista de närmaste raderna inom en viss radie utifrån en given punkt. Exempel:

SELECT *, ( 3959 * ACOS( COS( RADIANS(AAA) ) * COS( RADIANS( LAT ) ) * COS( RADIANS( LONG ) - RADIANS(OOO) ) + SIN( RADIANS(AAA) ) * SIN( RADIANS( LAT ) ) ) ) AS distance FROM tabellen_ifråga HAVING distance < X ORDER BY distance

Där är AAA latituden, OOO är longituden och X är avståndet (radien) utifrån utgångspunkten.

Problemet är inte frågan i sig (utan den får de svar den ska ha), utan mitt problem är prestandan. Att köra ovannämnda fråga kan ta ca 1 sekund och i vissa fall kan jag behöva att köra den 3 gånger på en sidvisning.

Tabeller ser ut enl. nedan:

ID - PK
LONG - VARCHAR(15) - INDEX
LAT - VARCHAR(15) - INDEX

Exempel på en koordinat kan vara:
LONG: -84.093177
LAT: 35.922934

Jag kör MySQL 5.1.58 och MyISAM som db-motor (standard)

Vad kan jag göra? Jag kör detta på en vanlig VPS hos Glesys med Debian 6, 64-bit

Tips mottages gladligen!

Senast redigerad av gregoff den 2011-11-30 klockan 21:38 Anledning: stavfel
gregoff är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-11-30, 21:50 #2
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
tartareandesire tartareandesire är inte uppkopplad
Supermoderator
 
Reg.datum: Jan 2004
Inlägg: 11 585
Jag brukar köra en betydligt enklare avståndsformel i databasqueryn och först därefter räkna mer exakt avstånd på de utvalda. Trigonometriska funktioner är tunga.
__________________
Full-stack developer, free for smaller assignments
tartareandesire är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-11-30, 21:54 #3
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
Citat:
Ursprungligen postat av tartareandesire Visa inlägg
Jag brukar köra en betydligt enklare avståndsformel i databasqueryn och först därefter räkna mer exakt avstånd på de utvalda. Trigonometriska funktioner är tunga.
Har du något exempel? Det exakta avståndet räknar jag ändå ut med php, så det är bara rätt urval jag behöver att utgå ifrån.
gregoff är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-11-30, 22:34 #4
Magnus_A Magnus_A är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: May 2006
Inlägg: 2 604
Magnus_A Magnus_A är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: May 2006
Inlägg: 2 604
Pröva gärna postgresql och ta fram avstånd direkt med ST_Distance i postgis.
Magnus_A är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-11-30, 22:35 #5
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
Citat:
Ursprungligen postat av Magnus_A Visa inlägg
Pröva gärna postgresql och ta fram avstånd direkt med ST_Distance i postgis.
Har tyvärr inte möjlighet att byta sql-databas.
gregoff är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-12-01, 03:33 #6
abergmans avatar
abergman abergman är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Feb 2010
Inlägg: 762
abergman abergman är inte uppkopplad
Mycket flitig postare
abergmans avatar
 
Reg.datum: Feb 2010
Inlägg: 762
Vad har du för prestanda på den maskinen? Har du provat att lägga på mer power och se om det blir något större förändring?
abergman är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-12-01, 06:58 #7
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
På en VPS hos Glesys kan man välja antal kärnor man vill ha, men inte hur "snabba" dom ska vara. Av eller på, typ.

Citat:
Ursprungligen postat av abergman Visa inlägg
Vad har du för prestanda på den maskinen? Har du provat att lägga på mer power och se om det blir något större förändring?
gregoff är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-12-01, 06:57 #8
Westmans avatar
Westman Westman är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Jun 2004
Inlägg: 4 021
Westman Westman är inte uppkopplad
Klarade millennium-buggen
Westmans avatar
 
Reg.datum: Jun 2004
Inlägg: 4 021
Varför köra den flera gånger, är det med olika X?
Westman är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-12-01, 09:38 #9
andreasp andreasp är inte uppkopplad
Nykomling
 
Reg.datum: Dec 2010
Inlägg: 5
andreasp andreasp är inte uppkopplad
Nykomling
 
Reg.datum: Dec 2010
Inlägg: 5
Själva grundproblemet här är att din query inte kan använda några index -- och blir därför väldigt slö eftersom den måste söka igenom hela tabellen och applicera din formel på alla rader. En snabbare CPU/biffigare server är knappast lösningen på problemet. 400 000 rader som är indexerade kräver inte någon extrem hårdvara att söka igenom snabbt.

En lösning skulle kunna vara typ:
SELECT *, <lång formel> AS distance FROM tabellen_ifråga WHERE (lat BETWEEN A AND B) AND (lon BETWEEN C AND D) HAVING distance < X ORDER BY distance

Där A, B, C och D är yttre gränser för platser som inte är intressanta. Om gränserna uppskattas vettigt så borde de skära bort den största delen av alla rader effektivt, och sen kan resten sökas igenom med den "tunga" formeln. Det är viktigt att lat/lon är indexerade så att de kan sökas effektivt (som du har skrivit att de redan är). Är inte helt säker på hur bra jämförelserna blir när du lagrar LAT/LONG som VARCHAR (minustecknet kan ställa till problem), det vore nog lämpligare (och garanterat effektivare) med en numerisk datatyp.

MySQL känns i det här fallet inte som den bästa lösningen på problemet. Som Magnus_A skriver så skulle PostgreSQL/PostGIS lösa problemet väldigt enkelt med ett spatial index och ST_Distance. MySQL har även en liknande spatial extension, som inte är speciell komplett, och är inte säker på att den kan lösa problemet effektivt överhuvudtaget (men jag kan ha fel!).

MongoDB har även stöd för spatial indexes och distans-queries, om du kunde lägga dina koordinater där och göra själva distans-sökningen där skulle det kunna vara ett alternativ.

Jag är rädd att det inte finns någon riktigt bra lösning med MySQL förutom någon slags workaround som ovan, som både är krånligare, mindre effektiv och framför allt: fulare!
andreasp är inte uppkopplad   Svara med citatSvara med citat
Oläst 2011-12-01, 09:50 #10
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
gregoff gregoff är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Jun 2010
Inlägg: 658
Känns ändå som att detta gav mig lite ledtrådar.

Istället för att använda en jobbig formel (som troligen är ganska krävande) så skulle man kanske kunna använda sig av en kvadrat istället för radie. Exempelvis att man ställer frågan utifrån LAT plus/minus X och LONG plus/minus X (med hjälp av t.ex. BETWEEN). Att jag får lite mer svar än jag skulle fått med den jobbiga formeln gör inte så mycket för det kan jag enkelt sortera bort med en liknande php-formel.

Kanske kunde vara något för mig att testa.

Kan nog vara värt att testa att konvertera columnen till lämplig datatyp med innan man gör något annat först.

Citat:
Ursprungligen postat av andreasp Visa inlägg
Själva grundproblemet här är att din query inte kan använda några index -- och blir därför väldigt slö eftersom den måste söka igenom hela tabellen och applicera din formel på alla rader. En snabbare CPU/biffigare server är knappast lösningen på problemet. 400 000 rader som är indexerade kräver inte någon extrem hårdvara att söka igenom snabbt.

En lösning skulle kunna vara typ:
SELECT *, <lång formel> AS distance FROM tabellen_ifråga WHERE (lat BETWEEN A AND B) AND (lon BETWEEN C AND D) HAVING distance < X ORDER BY distance

Där A, B, C och D är yttre gränser för platser som inte är intressanta. Om gränserna uppskattas vettigt så borde de skära bort den största delen av alla rader effektivt, och sen kan resten sökas igenom med den "tunga" formeln. Det är viktigt att lat/lon är indexerade så att de kan sökas effektivt (som du har skrivit att de redan är). Är inte helt säker på hur bra jämförelserna blir när du lagrar LAT/LONG som VARCHAR (minustecknet kan ställa till problem), det vore nog lämpligare (och garanterat effektivare) med en numerisk datatyp.

MySQL känns i det här fallet inte som den bästa lösningen på problemet. Som Magnus_A skriver så skulle PostgreSQL/PostGIS lösa problemet väldigt enkelt med ett spatial index och ST_Distance. MySQL har även en liknande spatial extension, som inte är speciell komplett, och är inte säker på att den kan lösa problemet effektivt överhuvudtaget (men jag kan ha fel!).

MongoDB har även stöd för spatial indexes och distans-queries, om du kunde lägga dina koordinater där och göra själva distans-sökningen där skulle det kunna vara ett alternativ.

Jag är rädd att det inte finns någon riktigt bra lösning med MySQL förutom någon slags workaround som ovan, som både är krånligare, mindre effektiv och framför allt: fulare!

Senast redigerad av gregoff den 2011-12-01 klockan 09:51 Anledning: stavfel
gregoff är inte uppkopplad   Svara med citatSvara med citat
Svara


Aktiva användare som för närvarande tittar på det här ämnet: 1 (0 medlemmar och 1 gäster)
 

Regler för att posta
Du får inte posta nya ämnen
Du får inte posta svar
Du får inte posta bifogade filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är GMT +2. Klockan är nu 00:07.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson
 
Copyright © 2017