Bitweises AND in Sql Server

8

Ich habe eine sehr typische Situation. Wir haben eine Tabelle namens Benutzer, die eine Spalte namens Branches (varchar 1000) hat.

Die Organisation kann 1000 Filialen haben. Wenn also ein Benutzer Zugriff auf die Zweige 1, 5 und 10 hat, sieht die Verzweigungszeichenfolge folgendermaßen aus:

1000100001000000000 ......

(d. h. 1 für eine Position, auf die ein Benutzer basierend auf der Zweignummer einen Verzweigungszugriff hat). Bitte geben Sie keine besseren Datenspeicheroptionen an. Das kommt von einer Legacy-Anwendung, die über Kontinente verteilt ist.

Nun, angesichts dieses Hintergrunds (und in Anbetracht dessen, dass es & gt; 10000 Benutzer geben kann), möchte ich nach allen Benutzern suchen, die Zugriff auf irgendeinen gegebenen Satz von Zweigen haben, z. Suchen Sie alle Benutzer, die Zugriff auf eine der Zweigstellen 10, 65, 90 oder 125 haben.

Eine einfache Lösung besteht darin, die gewünschte Reihe von Zweigen (z. B. 10, 65, 90, 125) in eine Verzweigungszeichenfolge (00000010100 usw.) umzuwandeln, dann mit einer skalaren UDF über beide Verzweigungszeichenfolgen zu iterieren und zuerst true zurückzugeben passendes Vorkommen, bei dem 2 Verzweigungsketten 1 haben, und falsch, wenn keine 1 an der gemeinsamen Position vorhanden ist.

Ansonsten habe ich auch die Möglichkeit, in der Anwendung in C # zu suchen. Einige dieser Benutzer sind privilegiert (ca. 1000 oder mehr) und ihre Daten werden in der Anwendung zwischengespeichert, da auf sie sehr häufig zugegriffen wird. Aber für andere Benutzer, die nicht privilegiert sind, sind Daten nur in db.

Ich habe hier zwei Fragen: 1) Gibt es für eine db-Suche einen besseren Weg als den von mir erwähnten UDF-Ansatz? 2) Für privilegierte Benutzer, was wäre besser in Bezug auf Leistung, Suche in der Anwendung (die weiter auf einer for-Schleife auf Verzweigung Strings wie in UDF oder als Linq Intersect-Operator auf 2-Zweig-Arrays, dh eine Linq-Schnittpunkt basieren kann an [1,5,9,50,80,200] und [6,90,256,300] etc.) Würde eine Datenbanksuche schnellere Ergebnisse oder eine anwendungsbasierte Suche erzeugen?

Berücksichtigen Sie, dass in beiden Fällen andere Parameter für die Suche vorhanden sein können, z. Nachname beginnt mit.

Mein aktueller Ansatz besteht darin, Zeilen in db für beide Situationen zuerst in anderen Parametern zu filtern (wie Nachname mit beginnt). Verwenden Sie dann eine skalare UDF, um diese Ergebnismenge basierend auf Verzweigungen zu filtern, und geben Sie dann die Ergebnisse zurück.

    
r_honey 22.03.2011, 18:54
quelle

6 Antworten

6

Mach es in SQL, es wird nur 100 mal schneller sein als in C # oder einem anderen Frontend.

Verwenden Sie die integrierte Nummerntabelle, um die lange Zeichenfolge in Positionen zu zerlegen (die Zahlenreihe reicht bis 2047).

Beispieltabellen

%Vor%

Beispiel mit allen übereinstimmenden Berechtigungen für eine Liste

%Vor%

Um Benutzer zu finden, die Zugriff auf mindestens einen Zweig in der Liste haben:

%Vor%

usw.

    
RichardTheKiwi 22.03.2011, 23:53
quelle
3

Sie könnten Zeichenfolgen der Form __1_1____1% für eine LIKE-Abfrage erstellen, um alle Benutzer zu finden, die Zugriff auf die Zweige 3, 5 und 10 haben.

Um diese Zeichenfolgen zu konstruieren, starten Sie am einfachsten mit einer Zeichenfolge von _ -Zeichen, die so lang ist wie die größte Zweignummer in Ihrer Gruppe (oder größer). Ersetzen Sie dann einzelne _ -Zeichen durch 1 -Zeichen und fügen Sie dann% am Ende an.

Ob dies schneller ist als eine Schleife in der Datenbank oder eine Schleife in Ihrer Anwendung, ich denke, Ihr bester Ansatz ist es, es einfach zu testen.

    
Yuliy 22.03.2011 19:16
quelle
2

Bitweise Gruppenmitgliedschaft:

Aus den Kommentaren gehe ich davon aus, dass wir keine Link-Tabelle für Gruppenmitgliedschaften verwenden können. Hier ist eine bitweise Lösung, die keine Strings verwendet. Es kann keine akzeptable Antwort sein, da die Anzahl der Bits die Anzahl der Gruppen ziemlich stark begrenzt. Durch die Verwendung von Ganzzahlen mit expliziten Wertvergleichen kann die Datenbank ihre Indizes jedoch effizient nutzen. Also habe ich es für den Fall hinzugefügt, dass die Anzahl der Gruppen / Rollen / was auch immer begrenzt ist, ausreichend ist.
PS: Entschuldige ein binär-dezimales Versehen, ich habe gerade Sachen im laufenden Betrieb angeschlossen. Fühlen Sie sich frei zu kommentieren und zu korrigieren, wenn ich irgendwelche Fehler habe.

Jeder Gruppe ist ein Bit zugewiesen:

%Vor%

Benutzergruppenmitgliedschaften werden mit bitweisem & amp; berechnet. Hier sind einige Beispiele mit den binären und dezimalen Äquivalenten:

%Vor%

Berechnen Sie nun mit Iteration von 1-N (N ist die Anzahl der Gruppen) und erhalten Sie eine Liste aller möglichen ganzzahligen Werte, zu denen eine bestimmte Gruppe beitragen kann. Zum Beispiel wird G1 in jeder ungeraden Zahl vorhanden sein:

%Vor%

Sie können dies mit einer Schleife von 1-1000 mit einem bitweisen UND des Dezimalwertes der Gruppe 1,2,4,8 usw. tun Bewahre die Werte im Speicher auf oder schiebe sie in die Tabelle, in der die möglichen Gruppen deiner Gruppen gespeichert sind, z. mögliche_Mitgliedschaften .

%Vor%

Wenn Sie eine Gruppentabelle mit der Spalte 'possible_memberships' haben, können Sie die Werte dort eingeben und Sie speichern vom Senden aller Werte über die Leitung und dem Zulassen, dass der Subselect in der Datenbank zwischengespeichert wird. p & gt;

%Vor%     
Derek Hulley 28.09.2015 14:22
quelle
1

Verwenden Sie eine LIKE-Abfrage. In Sql Server entspricht ein in einem LIKE-Ausdruck verwendeter _ jedem einzelnen Zeichen. Um die Benutzer in den Zweigen 1,5 und 10 zu bekommen, könnte man das so machen:

%Vor%

Dies ist nicht besonders effizient (es ist nicht sehr sargable), aber es sollte funktionieren und es ist wahrscheinlich nicht schlechter als Ihre udf-Option.

    
Joel Coehoorn 22.03.2011 19:18
quelle
0

AKTUALISIEREN

Dies ist keine praktikable Lösung mit einer 1000-Bit-Nummer. Ich werde es lassen, wenn jemand mit einer kleineren Anzahl von Optionen auf diesen Posten stößt.

Können Sie Änderungen am DB-Schema vornehmen? Wenn Sie eine berechnete Spalte hinzufügen können, die eine ganzzahlige Darstellung der Binärzahl enthält, die Sie in Ihrem varchar haben, können Sie mit der bitweisen Logik auswählen, worüber Sie gerade sprechen, und das ziemlich schnell in der DB.

Hier ist ein Beispiel von dem, worüber ich spreche:

%Vor%

Um Binär in eine Zahl zu konvertieren, müssten Sie wahrscheinlich eine UDF erstellen, die Sie aufrufen können, um die neue Spalte zu füllen. Ich stocherte ein wenig herum und fand das, was ein guter Ausgangspunkt zu sein scheint. Ich habe es noch nicht getestet, also sei vorsichtig:

%Vor%     
Abe Miessler 22.03.2011 19:26
quelle
0

Die bitweise Abfrage würde wahrscheinlich die Zeichenfolgenfunktionen übertreffen, obwohl die 1000-Bit-Ganzzahl nicht existiert. Wie jedoch aus der Zeichenkette abgeleitet werden kann, können Sie sie in eine bestimmte Anzahl von Integer-Mengen aufteilen und über diese abfragen. Sie müssen einfach die signifikanten Bits für jede Spalte verstehen und die Eingabe durch eine bestimmte Konstante entsprechend anpassen oder sie einfach in eine Menge von Bit, die Zeichenfolgen darstellt, konvertieren und in int umwandeln.

    
Jimmy Zimms 29.12.2012 15:57
quelle

Tags und Links