2017-02-15 5 views
0

Für eine bestimmte Liste von eindeutigen Elementen, nach dem Sortieren sie basierend auf ein paar Spalten in Batches, bekomme ich die Duplizierung von Elementen.Duplizierungsproblem mit MySQL-Sortierung auf mehrere Spalten

Es gibt zwei Tabellen:

- item_popularity_tbl: 
    iid (UINT, PK) pplt (UTINYINT) 

- item_cat_id_tbl: 
    iid (UINT, PK) cid (UTINYINT) 

Where: 
    iid: item ID, unique values in the tables 
    cid: cat ID, values in the range (1, 15). Multiple items can have same cid. 
    pplt: popularity, vals in the range (1, 10). Multiple items can have same pplt. 

eine Liste von Element-IDs gegeben, die alle einzigartig, ich brauche es von cid ASC zu bestellen und dann pplt DESC.

Ich verwende die folgenden SQL (MySQL) Code, um es zu erreichen:

# python code snippet 
def db_get_items_sorted(conn, iid_list, offset, limit): 
    n1 = ','.join(['%s'] * len(iid_list)) 
    # 
    sql_stmt = ("SELECT a.iid, a.cid, b.pplt " 
       "FROM pclg.item_cat_id_tbl  AS a " 
      "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
       "WHERE a.iid IN (%s) " 
       "ORDER BY a.cid ASC, " 
         "b.pplt DESC " 
       "LIMIT %s,%s") % (n1, offset, limit) 
    # 
    return conn.query(sql_stmt % tuple(iid_list)) 

I db_get_items_sorted nennen (...) in Chargen von 10 Getestet habe ich diese mit Eingang iid_list von 58 Elementen (unique) , gegen voll besetzte Tabellen mit eindeutigen iids. Für jeden Aufruf gibt mysql eindeutige 10 iids mit der richtigen Sortierung zurück, wie angefordert. Aber wenn ich die Batches verkette, um die letzten 58 Items zu erstellen, merke ich, dass mehrere Items (iid) in der Liste dupliziert sind (und für diese sind alle zurückgegebenen Spalten die gleichen, im Grunde vollständige Duplizierung). Zum Beispiel 48 eindeutige Zeilen und 10 Duplikate.

Wenn ich db_get_items_sorted (...) mit Offset 0 und Limit 58 aufrufe, gibt es keine IDD-Duplikate. Allerdings muss ich kleine Chargen aufrufen, da wir diese Sortierung für mehrere tausend Artikel durchführen können.

Frage ist: Wie erreicht man Einzigartigkeit über Chargen hinweg?

+0

Wenn ein separater Thread Einfügen oder Löschen von Datensätzen, wie Sie die Dosierung tun, dann 'OFFSET' ist durcheinander. –

+0

@RickJames Das ist ein guter Punkt, Rick. In diesem Fall ist dieses Szenario jedoch nicht vorhanden, eine Art von statischen Tabellen im Moment. Die Verwendung von DISTINCT, wie von scaisEdge unten erwähnt, löst das Problem. Aber, nicht klar, warum wir DISTINCT brauchen und warum Duplikate passieren. – Ethan

+1

'JOIN' bläht die Anzahl der Zeilen auf. –

Antwort

0

Ich wollte nicht DISTINCT verwenden, um das Problem zu lösen. Ich war mir nicht sicher, warum die Verdoppelung der Reihen überhaupt stattfand, daher wollte ich das ansprechen.

Unten ist die Lösung, eine Spalte iid mit einzigartigen vals Verwendung in der ORDER BY:

 sql_stmt = ("SELECT a.iid, a.cid, b.pplt " 
        "FROM pclg.item_cat_id_tbl  AS a " 
       "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
        "WHERE a.iid IN (%s) " 
        "ORDER BY a.cid ASC, " 
          "b.pplt DESC, a.iid DESC " 
        "LIMIT %s,%s") % (n1, offset, limit) 

TL; DR: Die Vervielfältigung geschieht, wie wir LIMIT zusammen mit ORDER Verwendung wurden BY und die Säulen in ORDER BY verwendet haben keine eindeutigen Vals.

Gründe:

  • LIMIT kehrt der Moment sie die erforderliche Anzahl der Zeilen, die die Abfrage erfüllen erfährt.

  • Wenn eine Spalte mit nicht eindeutigen Werten mit ORDER BY verwendet wird, müssen die Zeilen, die dieselben Werte dieser Spalten enthalten, keine deterministische Reihenfolge haben.

Also, mit LIMIT und ruft diese Routine mehrere Male (bis sie schließlich verketten um das Endergebnis zu produzieren), mysql lief die ORDER BY mehrmals und Zeilen mit gleichen val für Spalten (in der Reihenfolge verwendet, BY) waren über diese Anrufe nicht geordnet - dh ihre Positionen waren nicht konstant. LIMIT M, N gibt jedoch Zeilen aus dem spezifischen (M, N) -Fenster des ORDER BY-Ergebnisses zurück.

Dies führte zu dem endgültigen verketteten Ergebnis, das doppelte Zeilen enthielt.

Ref: https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html

1

Sie könnten mit disquare an der Abfrage arbeiten, so dass die Abfrage selbst Duplikate entfernt.

sql_stmt = ("SELECT DISTINCT a.iid, a.cid, b.pplt " 
       "FROM pclg.item_cat_id_tbl  AS a " 
      "INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid " 
       "WHERE a.iid IN (%s) " 
       "ORDER BY a.cid ASC, " 
         "b.pplt DESC " 
       "LIMIT %s,%s") % (n1, offset, limit) 
+0

Danke, das sollte es lösen. Werde es auf meine Daten testen und zurückkommen. Ein verwandter Anwendungsfall mit leichtem Mod: Was ist, wenn iid nicht 100% einzigartig ist? Nehmen wir an, es wird als Zeitstempel (mit Min-Granularität) für eine Kommentartabelle verwendet, und es gibt Instanzen mehrerer Kommentare, die in derselben Zeitmarke in einer anderen Tabelle enthalten sind. Wenn es hilft, kann ich diesen Anwendungsfall zu der Abfrage hinzufügen. – Ethan

+0

Offensichtlich arbeitet die distinct-Klausel tatsächlich an unterschiedlichen Werten und daher ist es wichtig, die tatsächlich für Ihren Zweck benötigten Spalten (oder Spaltendarstellungen) auszuwählen. Bei Zeilen, die kleiner als die Werte im Zeitstempel sind, können Sie diese Werte gruppieren mit Funktionen Zeit wie Minute(). oder. Stunde oder irgendetwas, das du magst – scaisEdge

+0

Sagst du, dass wir die einzigartige comment_id dort benutzen und DISTINCT darauf benutzen? (Ich habe die Abfrage von mir aktualisiert). – Ethan

Verwandte Themen