Frage

Ich habe eine Anforderung, eine Liste möglicher Duplikate zu erzeugen, bevor ein Benutzer eine Entität in der Datenbank speichert und warnen sie über die möglichen Duplikate.

Es gibt 7 Kriterien, auf denen wir die Duplikate und wenn mindestens 3 Spiel überprüfen sollten, sollten wir diese Flagge bis an den Benutzer. Die Kriterien werden alle Spiele auf ID, so dass es kein Fuzzy-String-Matching benötigte aber mein Problem kommt von der Tatsache, dass es viele Möglichkeiten gibt (99 Wege, wenn ich meine Summen corerctly getan habe) für mindestens 3 Elemente aus dem Übereinstimmen Liste von 7 possibles.

Ich will nicht 99 getrennte db-Abfragen zu tun haben, um meine Suchergebnisse und noch will ich, um die ganze Menge wieder aus dem db und Filter auf der Client-Seite. Wir sind wahrscheinlich nur reden von ein paar Zehntausende von Datensätzen zur Zeit, aber das wird in die Millionen wachsen, wie das System reift.

Jeder bekam keine thoughs eines schönen effizienteste Weg, dies zu tun? Ich erwäge eine einfache OR-Abfrage die Datensätze zu erhalten, wo mindestens ein Feld aus der db entspricht und dann auf dem Client einige Verarbeitung zu tun, es zu filtern, einige mehr, aber einige der Felder haben eine sehr geringe Mächtigkeit und werden nicht wirklich reduzieren die Zahlen durch eine riesige Menge.

Danke Jon

War es hilfreich?

Lösung

OR und CASE Summierung funktioniert, ist aber ziemlich ineffizient, da sie keine Indizes verwenden.

Sie müssen UNION machen für Indizes verwendbar sein.

Wenn ein Benutzer betritt name, phone, email und address in die Datenbank, und Sie möchten alle Datensätze überprüfen, die zumindest 3 dieser Felder übereinstimmen, können Sie ausgeben:

SELECT  i.*
FROM    (
        SELECT  id, COUNT(*)
        FROM    (
                SELECT  id
                FROM    t_info t
                WHERE   name  = 'Eve Chianese'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   phone = '+15558000042'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   email = '42@example.com'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   address = '42 North Lane'
                ) q
        GROUP BY
                id
        HAVING  COUNT(*) >= 3
        ) dq
JOIN    t_info i
ON      i.id = dq.id

Dies wird Indizes auf diesen Feldern verwenden und die Abfrage wird schnell.

Lesen Sie diesen Artikel in meinem Blog für Details:

  • Passende 3 von 4 : wie einen Datensatz entsprechen, die mindestens 3 von 4 möglichen Bedingungen

Siehe auch diese Frage der Artikel basiert auf.

Wenn Sie eine Liste von DISTINCT Werte in den vorhandenen Daten haben wollen, können Sie wickeln gerade diese Abfrage in einer Unterabfrage:

SELECT  i.*
FROM    t_info i1
WHERE   EXISTS
        (
        SELECT  1
        FROM    (
                SELECT  id
                FROM    t_info t
                WHERE   name  = i1.name
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   phone = i1.phone
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   email = i1.email
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   address = i1.address
                ) q
        GROUP BY
                id
        HAVING  COUNT(*) >= 3
        )

Beachten Sie, dass dieser DISTINCT nicht transitiv ist. Wenn A Spiele B und B Spiele C, bedeutet dies nicht, dass A Spiele C

Andere Tipps

Sie könnten so etwas wie die folgenden wollen:

SELECT id
FROM 
    (select id, CASE fld1 WHEN input1 THEN 1 ELSE 0 "rule1",
        CASE fld2 when input2 THEN 1 ELSE 0 "rule2",
        ...,
        CASE fld7 when input7 THEN 1 ELSE 0 "rule2",
    FROM table)
WHERE rule1+rule2+rule3+...+rule4 >= 3

Dies ist nicht getestet, aber es zeigt einen Weg, dies zu bewältigen.

Was DBS verwenden Sie? Eine gewisse Unterstützung unter Verwendung eines solchen Einschränkungen, die durch Server-Side-Code verwendet wird.

Haben Sie darüber nachgedacht, eine gespeicherte Prozedur mit einem Cursor? Sie könnten dann Ihre OR Abfrage tun und dann die Datensätze für die Spiele suchen one-by-one Schritt durch. eine gespeicherte Prozedur Sie erlauben würde, alle die Prüfung auf dem Server zu tun.

Aber ich denke, ein Tabellen-Scan mit Millionen von Datensätzen wird immer langsam sein würde. Ich glaube, Sie trainieren sollten, welche der 7 Felder am ehesten entsprechen, werden sicherstellen, dass diese indiziert werden.

Ich gehe davon aus Ihrem System versucht, Tag-IDs eines bestimmten Post anzupassen, oder etwas ähnliches. Dies ist eine Multi-to-Multi-Beziehung, und Sie sollten drei Tabellen müssen damit umgehen. Ein für den Posten, ein für Tags und ein für Post und Tags Beziehung.

Wenn meine Annahmen korrekt sind dann der beste Weg, dies zu handhaben ist:

SELECT postid, count(tagid) as common_tag_count
FROM posts_to_tags
WHERE tagid IN (tag1, tag2, tag3, ...)
GROUP BY postid
HAVING count(tagid) > 3;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top