Ich möchte benutzerdefinierte Tags für Benutzerkäufe bei jeder Transaktion speichern. Wenn Benutzer beispielsweise Schuhe gekauft haben, sind dies Tags "SPORTS", "NIKE", SHOES, COLOUR_BLACK, SIZE_12,..
Diese Tags sind diejenigen Verkäufer, die daran interessiert sind, eine Anfrage zu stellen, um die Verkäufe zu verstehen.
Meine Idee ist, wann immer ein neues Tag hereinkommt, neuen Code (so etwas wie Hashcode, aber sequentiell) für dieses Tag zu erstellen, und der Code beginnt mit "a-z"
26 Buchstaben und "aa, ab, ac...zz"
geht dann weiter. Behalten Sie nun alle in einer Transaktion angegebenen Tags in der einen Spalte, die tag (varchar)
durch Trennen mit aufgerufen wird "|"
.
Nehmen wir an, Mapping ist (auf Anwendungsebene)
"SPORTS" = a
"TENNIS" = b
"CRICKET" = c
...
...
"NIKE" = z //Brands company
"ADIDAS" = aa
"WOODLAND" = ab
...
...
SHOES = ay
...
...
COLOUR_BLACK = bc
COLOUR_RED = bd
COLOUR_BLUE = be
...
SIZE_12 = cq
...
Wenn Sie also die oben genannte Kauftransaktion speichern, tag="|a|z|ay|bc|cq|"
sieht das Tag wie folgt aus. Jetzt kann der Verkäufer die Anzahl der verkauften SCHUHE suchen, indem er die WHERE
Bedingung hinzufügt tag LIKE %|ay|%
. Jetzt ist das Problem, dass ich keinen Index (Sortierschlüssel in Rotverschiebungsdatenbank) für "LIKE beginnt mit%" verwenden kann. Wie kann man dieses Problem lösen, da ich möglicherweise 100 Millionen Datensätze habe? Ich möchte keinen vollständigen Tabellenscan.
Gibt es eine Lösung, um dies zu beheben?
Update_1: Ich habe das bridge table
Konzept (Querverweistabelle) nicht befolgt, da ich nach dem Durchsuchen der angegebenen Tags eine Gruppierung der Ergebnisse durchführen möchte. Meine Lösung gibt nur eine Zeile an, wenn zwei Tags in einer einzigen Transaktion übereinstimmen, aber die Brückentabelle gibt mir zwei Zeilen? dann wird meine Summe () verdoppelt.
Ich habe einen Vorschlag wie unten
EXISTS (SELECT 1 FROM transaction_tag WHERE tag_id = 'zz' und trans_id = tr.trans_id) in der WHERE-Klausel einmal für jedes Tag (Hinweis: Es wird davon ausgegangen, dass tr ein Alias für die Transaktionstabelle in der umgebenden Abfrage ist).
Ich bin dem nicht gefolgt; da ich AND- und OR-Bedingungen für die Tags ausführen muss, Beispiel ("SPORTS" UND "ADIDAS") ---- "SHOE" AND ("NIKE" ODER "ADIDAS")
Update_2: Ich bin dem Bitfeld nicht gefolgt, da ich nicht weiß, dass Redshift diese Unterstützung bietet. Ich gehe auch davon aus, dass mein System mindestens 3500 Tags haben wird, und ordne jedem ein Bit zu. Dies ergibt 437 Bytes für jede Transaktion, obwohl für eine Transaktion nur maximal 5 Tags angegeben werden können. Irgendeine Optimierung hier?
Lösung_1:
Ich habe darüber nachgedacht, min (SMALL_INT) und max value (SMALL_INT) zusammen mit der Tags-Spalte hinzuzufügen und darauf einen Index anzuwenden.
so etwas wie das
"SPORTS" = a = 1
"TENNIS" = b = 2
"CRICKET" = c = 3
...
...
"NIKE" = z = 26
"ADIDAS" = aa = 27
Meine Spaltenwerte sind also
`tag="|a|z|ay|bc|cq|"` //sorted?
`minTag=1`
`maxTag=95` //for cq
Und Abfrage für die Suche Schuh (ay = 51) ist
maxTag <= 51 AND tag LIKE %|ay|%
Und die Abfrage für die Suche nach Schuh (ay = 51) UND SIZE_12 (cq = 95) ist
minTag >= 51 AND maxTag <= 95 AND tag LIKE %|ay|%|cq|%
Wird dies einen Nutzen bringen? Bitte schlagen Sie Alternativen vor.
quelle
transaction_tag
Tabelle betrachtet, die verknüpft isttransaction
undtag
in einer Viele-zu-Viele-Beziehung steht? In Bezug auf die Leistung ist es in der Regel eine schlechte Idee, mehrere Werte als einfach begrenzten Text in einer einzelnen Spalte zu speichern.INNER JOIN
zutransaction_tag
einmal für jeden Tag angefordert oder unter Verwendung vonEXISTS (SELECT 1 FROM transaction_tag WHERE tag_id = 'zz' and trans_id = tr.trans_id)
in derWHERE
einmal Klausel für jeden Tag (Hinweis: nimmt an tr ein Alias für das isttransaction
Tabelle in der umgebenden Abfrage).Antworten:
Ich bin immer noch davon überzeugt, dass die Verwendung einer Viele-zu-Viele-Nachschlagetabelle (einer Brückentabelle) hier immer noch die beste Option ist. Ihre Bedenken hinsichtlich des Abgleichs mehrerer Zeilen können durch ein ordnungsgemäßes Abfragedesign behoben werden. Angenommen, Ihre Tabellen sind:
Für jeden Kauf können mehrere Tags festgelegt werden (ohne Limit). Aus Spaß habe ich die Möglichkeit hinzugefügt, die Tags nach TagType zu kategorisieren. Vielleicht enthält sie Dinge wie "ProductType", "Marke", "Farbe", "Sport", so dass Sie eine Möglichkeit haben , dass die „Schuhe“ zu sagen , ist ein „Product“ tag „Nike“ ist eine Marke - Tag, und „Fußball“ ist ein Sport - Tag.
Wenn Sie dann abfragen möchten (und nur einzelne Zeilen zurückgeben möchten), gehen Sie einfach wie folgt vor:
Wenn Sie ausgefallenere Kombinationssuchen durchführen müssen (Kauf von Nike-Schuhen oder Adidas-Schuhen finden) , muss Ihre Anfrage auch ausgefallener sein:
Auch hier wird für jeden Einkauf eine einzelne Zeile zurückgegeben, die Ihrer gewünschten Tag-Kombination entspricht.
quelle
Der übliche Weg, um ein solches Problem zu lösen, ist die Verwendung eines Bitfelds .
Sie würden also eine Tags-Tabelle erstellen und diese über eine n: m-Tabelle mit den Verkaufszahlen oder Produkten verknüpfen. Dann würden Sie in der Tags-Tabelle für jedes Tag einen eindeutigen Bitwert als Potenz von 2 zuweisen, z. B.
1, 2, 4, 8, ..., 1024, 2048, ...
fürsports, tennis, cricket, ...
und so weiter.Mit können
bit_or
Sie diese Werte dann zu einem einzigen numerischen Wert zusammenfassen und neben den Produkt- oder Verkaufszahlen speichern. Zum Beispiel werden die Tags "Sport" und "Cricket" auf einem Produkt zu 5.Wenn die Bitgröße des verfügbaren numerischen Typs nicht ausreicht, um alle Ihre Tags zu speichern, verwenden Sie mehrere dieser Felder und speichern Sie die Nummer oder den Spaltennamen des Felds und den Bitwert mit dem Tag.
Verwenden Sie dann zum Abfragen Klauseln des Formulars:
flags & 1024 = 1024
oderflags & 1024 <> 0
= 10. Flag gesetztSie können jetzt einen beliebigen booleschen Ausdruck für die Flags ausführen. Wenn Sie ein einzelnes Feld für alle Farben festlegen, können Sie auch andere Tricks ausführen, z. B. die Abfrage von Produkten mit einem Color-Tag:
colorflags <> 0
und so weiter.Da Sie sich in einer spaltenorientierten Datenbank befinden (Rotverschiebung),
&
wird diese nur einmal pro eindeutigem Wert in der Spalte ausgeführt. Abhängig von der Implementierung wird die Datenbank dies weiter reduzieren, indem sie die&
-klausel analysiert und Größenbeschränkungen durch Sortierreihenfolge der Spaltenwerte verwendet (kostenlos).Und wenn Sie das letzte Stück Leistung benötigen, können Sie Tricks ausführen, indem Sie Statistiken zu den Flags und Abfragen sammeln und diese intelligent gruppieren. Ich gehe davon aus, dass in dem von Ihnen beschriebenen Anwendungsfall (Summengruppe nach Filterung durchführen) die Leistung, die Sie dadurch erzielen könnten, im Vergleich zu den Berechnungskosten vernachlässigbar ist.
quelle
Tabellen
Sie benötigen purchaseDetail, um alle Tags dem Artikel zuzuordnen
quelle