webForumDet fria alternativet

Databasdesign: Mycket snabbare med = än LIKE?

Databaser & SQL

1 svar · 399 visningar · startad av erciz

Medlem sedan maj 20011 826 inlägg
Frågan#1

Jag håller på med en namnnormeringsfunktion. Den funkar så att användaren skriver in ett efternamn t.ex. Ericsson, sen ska en normeringsfunktion ersätta det med Eriksson som är den normerade stavningen, för att underlätta sökningar på personer som har samma namn som "låter" lika men stavas olika.

Nu har jag en databastabell likt:

+--------------+-----------------+
| normeratNamn | varianter       |
+--------------+-----------------+
| Eriksson     | Ericsson Ersson |
+--------------+-----------------+

Dvs det blir ett efternamn på varje rad.

När jag gör sökningar sen så måste jag matcha i kolumnen varianter med efternamn = normeratNamn OR efternamn LIKE 'Ericsson ' eftersom varianter kan innehålla flera värden (inte så bra databasdesign). Visst borde väl det här bli väldigt slött, erftersom LIKE måste jobba sig igenom varje rad för att hitta en match, det går liksom inte att dra nytta av ett bra index?

Vore det bättre att ha flera rader för varje normerat Efternamn likt:

+--------------+----------+
| normeratNamn | variant  |
+--------------+----------+
| Eriksson     | Ericsson |
+--------------+----------+
| Eriksson     | Ersson   |
+--------------+----------+

Då går det väl bättre att skapa ett index, men det blir istället många fler rader och det blir många med samma värde i den första kolumnen. Vad tror ni är bäst ur prestandasynpunkt. Är det segt med LIKE-delar i SQL, bör det undvikas om det går eller?

Medlem sedan dec. 19995 874 inlägg
#2

En kolumn skall aldrig innehålla flera värden, precis som du säger.

Din andra version är mycket bättre rent prestandamässigt. Då skapar du ett index på variant-kolumnen.

OR kan ge prestandaproblem och ett bra tips om du bara gör OR på några få kolumner är att göra en UNION (eller UNION ALL, om du vet att du inte kommer få dubletter), exempelvis:

SELECT normeratNamn as namn FROM names WHERE normeratNamn = 'eriksson'
UNION ALL
SELECT variant as namn FROM names WHERE variant = 'eriksson'

Det kan vara så att den kan använda indexen bättre då, dessutom kan du skapa två separata index helt optimerade för en enda fråga.

Jag vet inte vilken databasmotor du jobbar med, men exempelvis sql-server har en funktion som heter soundex, exempelvis:

SELECT SOUNDEX('eriksson') -- returnerar E625
SELECT SOUNDEX('ericsson') -- returnerar E625
SELECT SOUNDEX('ersson') -- returnerar E625
SELECT SOUNDEX('svensson') -- returnerar S152

Som du ser så tycker soundex att de tre första strängarna är ganska lika. En annan funktion är difference som räknar antal skillnader i en sträng.

Läs mer om soundex och difference:
http://msdn.microsoft.com/en-us/library/aa259235(SQL.80).aspx

När det gäller din fråga om = är mycket snabbare än like, så måste jag svara. Det beror på.

Om du har en tabell och ställer din frågan mot en indexerad kolumn så kan exempelvis
SELECT name FROM names WHERE name LIKE 'eriks%' använda indexet och därmed bli väldigt snabb. I senare versioner av sql-server kan det faktiskt även hända att den kan använda indexen vid frågor som WHERE name LIKE '%eriks%', men det är inte lika vanligt.

250 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
123 ms — deklarationer (db)
0 ms — hämta statistik (cache)
124 ms — hämta tråd, inlägg och bilagor (db)
122 ms — ändringar (db)