Suche doppelter Datensätze zu langsam

From: Thomas Uzunoff <postgresql(at)grizzlycrm(dot)de>
To: pgsql-de-allgemein(at)postgresql(dot)org
Subject: Suche doppelter Datensätze zu langsam
Date: 2012-11-13 08:25:54
Message-ID: 50A20412.2050001@grizzlycrm.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-de-allgemein

Hallo,

ich möchte in einer Tabelle doppelte Datensätze aufspüren. Hierzu
benutze ich SOUNDEX() zur phonetischen Suche. Das Problem ist, dass die
bisherige Version der Prüfung bei den Kriterien name und strasse nicht
alle beabsichtigten Daten findet, nämlich aus der folgenden Tabelle nur
die ersten beiden (BMW) Datensätze. Es sollen aber zum Beispiel auch die
Datensätze in den Zeilen 3 und 4 gefunden werden.

id name strasse
----------------------------------------------------
1 BMW Hauptstrasse 55
2 BMW Hauptstrasse 57
3 Siemens Hochweg 40
4 Siemens
5 Post Bonner Strasse 90

Dazu habe ich die letzten beiden Zeilen der Abfrage mit den ORs
erweitert. Logisch scheint auch das richtige Ergebnis rauszukommen, nur
ist es jetzt sehr sehr langsam und dass bei einer Menge von gerade mal
10.000 Datensätzen. Die LENGTH Funktion dient dazu herauszufinden, ob an
die SOUNDEX() etwas Auswertbares übergeben wurde und falls das nicht der
Fall ist (also der SOUNDEX-Wert nicht 4 Zeichen lang ist), der Datensatz
trotzdem als Dublette gefunden werden kann.

SELECT DISTINCT
company1.company__id
, company1.company__name
, company1.company__streetno
FROM
company company1
, company company2
WHERE
company1.company__id<>company2.company__id
AND
(SOUNDEX(company1.company__name)=SOUNDEX(company2.company__name) OR
LENGTH(SOUNDEX(company1.company__name))=0 OR
LENGTH(SOUNDEX(company2.company__name))=0)
AND
(SOUNDEX(company1.company__streetno)=SOUNDEX(company2.company__streetno)
OR LENGTH(SOUNDEX(company1.company__streetno))=0 OR
LENGTH(SOUNDEX(company2.company__streetno))=0)

Ich habe mir daraufhin die Ausführungspläne angesehen. Der
Ausführungsplan für obige Abfrage ist der folgende:

"HashAggregate (cost=4481104.91..4481184.91 rows=8000 width=57)"
" -> Nested Loop (cost=0.00..4480998.00 rows=14255 width=57)"
" Join Filter: ((company1.company__id <> company2.company__id)
AND ((soundex(company1.company__streetno) =
soundex(company2.company__streetno)) OR
(length(soundex(company1.company__streetno)) = 0) OR
(length(soundex(company2.company__streetno)) = 0)) AND
((soundex((company1.company__name)::text) =
soundex((company2.company__name)::text)) OR
(length(soundex((company1.company__name)::text)) = 0) OR
(length(soundex((company2.company__name)::text)) = 0)))"
" -> Seq Scan on company company1 (cost=0.00..489.00 rows=8000
width=57)"
" -> Materialize (cost=0.00..529.00 rows=8000 width=57)"
" -> Seq Scan on company company2 (cost=0.00..489.00
rows=8000 width=57)"

Wenn ich die ursprüngliche Abfrage ausführe, die so aussieht:

SELECT DISTINCT
company1.company__id
, company1.company__name
, company1.company__streetno
FROM
company company1
, company company2
WHERE
company1.company__id<>company2.company__id
AND (SOUNDEX(company1.company__name)=SOUNDEX(company2.company__name) )
AND
(SOUNDEX(company1.company__streetno)=SOUNDEX(company2.company__streetno))

Ist der Ausführungsplan dieser:

"HashAggregate (cost=2407.26..2423.26 rows=1600 width=57)"
" -> Merge Join (cost=2015.26..2395.26 rows=1600 width=57)"
" Merge Cond: (((soundex((company1.company__name)::text)) =
(soundex((company2.company__name)::text))) AND
((soundex(company1.company__streetno)) =
(soundex(company2.company__streetno))))"
" Join Filter: (company1.company__id <> company2.company__id)"
" -> Sort (cost=1007.63..1027.63 rows=8000 width=57)"
" Sort Key: (soundex((company1.company__name)::text)),
(soundex(company1.company__streetno))"
" -> Seq Scan on company company1 (cost=0.00..489.00
rows=8000 width=57)"
" -> Sort (cost=1007.63..1027.63 rows=8000 width=57)"
" Sort Key: (soundex((company2.company__name)::text)),
(soundex(company2.company__streetno))"
" -> Seq Scan on company company2 (cost=0.00..489.00
rows=8000 width=57)"

Ich habe den Eindruck, dass das Nested Loop mit der Verlangsamung etwas
zu tun hat, habe aber noch keinen Weg gefunden, postgres beizubringen,
den Nested Loop hier nicht zu verwenden.

Ich habe schon versucht, mit funktionionellen Indizes auf beide Felder
SOUNDEX(company__name) und SOUNDEX(company__streetno) die Suche zu
beschleunigen - hat aber auch nicht geholfen. Über eine Idee, wie ich
die obere Abfrage so beschleunigen kann, dass sie ähnlich schnell oder
noch besser als die untere Abfrage läuft, wäre ich sehr dankbar.

Danke & Grüße

Thomas

Browse pgsql-de-allgemein by date

  From Date Subject
Next Message Christopher Westerfield 2012-11-20 16:05:11 Frage zum aufsetzen eines multi-server gespanns
Previous Message Wolfgang Keller 2012-11-10 13:22:25 Re: Werkzeug für Datenbankanwendung gesucht