3

Ich verwende Azure-Tabellenspeicher, um Daten über Zeitstempelfilter abzurufen. Ich sehe, dass die Ausführung sehr langsam ist, da Timestamp kein Partitionsschlüssel oder Zeilenschlüssel ist. Ich habe Stackoverflow untersucht und festgestellt, dass der Zeitstempel in Ticks konvertiert und in Partition Key gespeichert werden soll. Ich tat das Gleiche und während ich Daten einfügte, nahm ich die untere Zeichenkette und die eingefügte Tick-Zeichenkette in den Partitionsschlüssel.Azure-Tabellenspeicher Abfrage von Partitionsschlüssel

string currentDateTimeTick = ConvertDateTimeToTicks(DateTime.Now.ToUniversalTime()).ToString(); 

public static long ConvertDateTimeToTicks(DateTime dtInput) 
{ 
    long ticks = 0; 
    ticks = dtInput.Ticks; 
    return ticks; 
} 

Das ist gut bis hier. Aber wenn ich versuche, die letzten 5 Tage Daten zu erhalten, kann ich den Haken gegen den Partitionsschlüssel nicht abfragen. Ich versuche, die letzten 5 Tage Daten zu bekommen. Was war mein Fehler im folgenden Code?

int days = 5; 
TableQuery<MyEntity> query = new TableQuery<MyEntity>() 
.Where(TableQuery.GenerateFilterConditionForDate("PartitionKey", QueryComparisons.GreaterThanOrEqual, "0"+DateTimeOffset.Now.AddDays(days).Date.Ticks)); 

Antwort

6

Sind Sie sicher, dass Sie Ticks als Partitionsschlüssel verwenden möchten? Dies bedeutet, dass jeder messbare 100-ns-Zeitpunkt zu einer eigenen Partition wird. Bei zeitbasierten Daten können Sie mit dem Partitionsschlüssel ein Intervall wie jede Stunde, Minute oder sogar Sekunde und dann einen Zeilenschlüssel mit dem aktuellen Zeitstempel angeben.

Dieses Problem beiseite lassen Sie mich Ihnen zeigen, wie Sie die Abfrage durchführen. Lassen Sie mich zuerst kommentieren, wie Sie den Partitionsschlüssel generieren. Ich schlage vor, Sie es wie folgt tun:

var partitionKey = DateTime.UtcNow.Ticks.ToString("D18"); 

nicht DateTime.Now.ToUniversalTime() Verwenden Sie die aktuelle UTC-Zeit zu bekommen. Es wird intern DateTime.UtcNow verwenden, dann konvertiert es in die lokale Zeitzone und ToUniversalTime() wird zurück in UTC konvertieren, die einfach verschwenderisch ist (und mehr Zeitaufwand, als Sie vielleicht denken).

Und Ihre Methode dient keinem anderen Zweck, als die Eigenschaft Ticks zu erhalten, so dass es nur Ihren Code komplexer macht, ohne irgendeinen Wert hinzuzufügen.

Hier ist, wie die Abfrage auszuführen:

var days = 5; 
var partitionKey = DateTime.UtcNow.AddDays(-days).Ticks.ToString("D18") 
var query = new TableQuery<MyEntity>().Where(
    TableQuery.GenerateFilterCondition(
    "PartitionKey", 
    QueryComparisons.GreaterThanOrEqual, 
    partitionKey 
) 
); 

Der Verteilungsschlüssel ist als 18 Zeichen String formatiert so dass Sie einen direkten Vergleich zu verwenden.

Ich schlage vor, dass Sie den Code verschieben, um den Partitionsschlüssel (und Zeilenschlüssel) in eine Funktion zu generieren, um sicherzustellen, dass die Schlüssel auf die gleiche Weise im gesamten Code generiert werden.

Der Grund, warum 18 Zeichen verwendet werden, ist, weil der Ticks Wert eines DateTime heute sowie viele Tausende von Jahren in der Zukunft 18 Dezimalziffern verwendet. Wenn Sie entscheiden, Ihren Partitionsschlüssel auf Stunden, Minuten oder Sekunden anstatt auf 100 ns zu setzen, können Sie die Länge des Partitionsschlüssels entsprechend verkürzen.

+0

Die Auswahl von D18 würde mich verwirren, denn wenn Ihre Daten nicht auf ~ 300AD zurückgehen, entspricht dies dem Standard ToString(), der G19 verwendet. Ich empfehle die Verwendung von D19, wenn die Leute es sehen, können sie denken "ah, weil Longs auf 19 Ziffern begrenzt sind." – user1676558

+0

@ user1676558: Allerdings werden Sie höchstwahrscheinlich keine Ticks als Partitionsschlüssel verwenden, obwohl es in der Frage steht.Wenn Sie beispielsweise Stunden als Partitionsschlüssel verwenden möchten, ist der resultierende Schlüssel eine 8-stellige Ganzzahl. Mit 'D8' als Format wird sichergestellt, dass Zahlen mit weniger als 8 Ziffern immer noch einen 8-stelligen Partitionsschlüssel mit vorangestellten Nullen enthalten. Sie haben jedoch recht, dass Sie zu irgendeinem vernünftigen Termin höchstwahrscheinlich nur 'ToString()' verwenden können, da alle Daten in nicht zu ferner Zukunft oder Vergangenheit immer 8 Ziffern für Stunden oder 18 Ziffern für Ticks usw. haben. Mein 'D #' soll eine allgemeine Lösung sein. –

5

Wie Martin vorschlägt, ist die Verwendung eines Zeitstempels als Partitionsschlüssel fast sicher nicht das, was Sie tun möchten.

Partitionen sind die Skalierungseinheit im Azure-Tabellenspeicher und repräsentieren mehr oder weniger die physische Segmentierung Ihrer Daten. Sie sind eine Skalierbarkeitsoptimierung, die es Ihnen ermöglicht, "Hardware" auf das Problem zu werfen, immer mehr Daten zu speichern, während akzeptable Antwortzeiten beibehalten werden (etwas, das traditionell schwer im Datenspeicher ist). Sie definieren die Partitionen in Ihren Daten, indem Sie jeder Zeile Partitionsschlüssel zuweisen. Es ist fast nie wünschenswert, dass jede Zeile in einer eigenen Partition lebt.

In ATS wird der Zeilenschlüssel zu Ihrem eindeutigen Schlüssel innerhalb einer bestimmten Partition. Die Kombination aus Partitionsschlüssel + Zeilenschlüssel ist also der eindeutige Schlüssel in der gesamten ATS-Tabelle.

Es gibt viele Ratschläge für die Auswahl eines gültigen Partitionsschlüssels und Zeilenschlüssels ... von denen keiner generalisiert ist. Dies hängt von der Art Ihrer Daten, Ihren erwarteten Abfragemustern usw. ab.

Wählen Sie einen Partitionsschlüssel, der Ihre Daten in einer angemessen verteilten "Gruppe von Buckets" zusammenfasst. Wenn alle Dinge gleich sind, wenn Sie 1 Million Zeilen in Ihrem Tisch haben, ist es oft sinnvoll, 10 Eimer mit je 100.000 Reihen zu haben ... oder vielleicht 100 Eimer mit jeweils 10.000 Reihen. Zur Abfragezeit müssen Sie die Partition (en) auswählen, die Sie abfragen, sodass die Anzahl der Buckets für Sie von Bedeutung sein kann. "Buckets" entsprechen häufig einem natürlichen Segmentierungskonzept in Ihrer Domäne ... einem Bucket, um jeden US-Bundesstaat zu repräsentieren, oder einem Bucket, um jede Abteilung in Ihrem Unternehmen usw. darzustellen. Beachten Sie, dass es nicht notwendig (oder oft möglich) ist, perfekt zu haben verteilte Eimer ... so nah wie möglich, mit vertretbarem Aufwand.

Ein Beispiel für eine absichtlich ungleiche Verteilung ist, wenn Sie Abfragemuster nach Bucket variieren möchten ... Bucket A erhält viele billige, schnelle Abfragen, Bucket B weniger, teurere Abfragen usw. Oder Vielleicht bleiben die Daten des Buckets A statisch, während sich Daten des Buckets B häufig ändern. Dies kann auch mit mehreren Tabellen erreicht werden ... also gibt es keine "one size fits all" Antwort.

Angesichts der begrenzten Kenntnisse, die wir von Ihrem Problem haben, mag ich Martins Ratschlag, eine Zeitspanne als Ihren Partitionsschlüssel zu verwenden. Kleine Spannen führen zu vielen Partitionen und machen (unter anderem) Abfragen, die mehrere Zeitspannen nutzen, relativ teuer. Größere Spannen führen zu geringeren Aggregationskosten über Spannen hinweg, führen jedoch zu größeren Partitionen und somit zu teureren Abfragen innerhalb einer Partition (außerdem wird die Identifizierung eines geeigneten Zeilenschlüssels potenziell schwieriger).

Am Ende werden Sie wahrscheinlich mit ein paar Optionen experimentieren müssen, um den am besten geeigneten für Ihre Daten und beabsichtigten Abfragen zu finden.

Ein weiterer Ratschlag ... scheuen Sie sich nicht, Daten in mehreren Datenspeichern zu duplizieren, um sie an unterschiedlichste Abfragetypen anzupassen. Nicht jede Abfrage funktioniert effektiv gegen eine einzelne Schema- oder Speicherkonfiguration. Der Aufwand, der zum Synchronisieren von Daten zwischen Speichern erforderlich ist, ist möglicherweise geringer als die erforderliche Biegeabfragetechnologie X.

more on Partition and Row key choices

also here

Best of luck!

+0

Danke für sehr nützliche Sachen. Wirklich schätzen Sie Ihre Zeit. – Kurkula

+0

Dies ist bei weitem eine der besten Erklärungen zu diesem Thema. Vielen Dank!!! –

+0

Danke für die netten Worte, froh zu helfen :-) – JoshL

1

Eine Sache, die in den obigen Antworten nicht erwähnt wurde, ist, dass Azure erkennt, wenn Sie fortlaufende, immer steigende oder immer abnehmende Werte für Ihren Partitionsschlüssel verwenden und "Bereichspartitionen" erstellen. Bereichspartitionen gruppieren Entitäten mit sequenziellen eindeutigen PartitionKey-Werten, um die Leistung von Bereichsabfragen zu verbessern. Ohne Bereichspartitionen, wie oben erwähnt, muss eine Bereichsabfrage die Partitionsgrenzen oder Servergrenzen überschreiten, was die Abfrageleistung verringern kann. Bereichsunterteilungen passieren unter der Haube und werden von Azure entschieden, nicht von dir.

Jetzt, wenn Sie Masseneinfügungen machen wollen, sagen wir einmal pro Minute, müssen Sie Ihre Zeitstempelpartitionierungsschlüssel, sagen wir, Ticks auf die nächste Minute aufgerundet werden. Sie können nur Masseneinfügungen mit demselben Partitionsschlüssel durchführen.

Verwandte Themen