Hintergrund
Ich versuche, eine "Besuchs" -Sequenz zu erstellen. Wenn ein Tier im Wesentlichen am selben Ort entdeckt wird ( General_Location
), zählt es als einzelner Besuch. Wenn es jedoch an einen anderen Ort und dann zurück geht, ist dies ein zusätzlicher Besuch am selben Ort. Wenn also ein Tier in einer Location
Sequenz erkannt wird, in der
A1, A2, A3, A3, A3, A1, B2, D4, A2
z. B. alle A (n) General_Location
-Stellen zu "A" gehören, hat dies die ersten 6 Erkennungen als Besuch 1 (@A), als nächstes als Besuch 2 (@B), als nächstes als Besuchen Sie 3 (@D), als nächstes Besuch 4 (zurück @A).
Wie LAG
und LEAD
ist in SQL Server 2008R2 nicht verfügbar (noch ist UNBOUNDED PRECEDING
in der PARTITION
ing - Klausel), ich bin eine Behelfslösung , wie in diesem Versuch beschrieben SQL Authority Blog - Eintrag .
Ich habe folgende Probleme mit dem Speicher (ganz zu schweigen von der Rechenzeit):
WITH s AS (
SELECT
RANK() OVER (PARTITION BY det.Technology, det.XmitID ORDER BY DetectDate ASC, ReceiverID ASC) as DetID,
COALESCE(TA.AnimalID, det.Technology+'-'+cast(da.XmitID AS nvarchar), 'BSVALUE999') as AnimalID,
det.Technology, det.XmitID, DetectDate, det.location as Location, RL.General_Location as GLocation, ReceiverID
FROM
Detections_with_Location as det JOIN
Receiver_Locations as RL
ON det.Location=RL.Location LEFT OUTER JOIN
Tagged_Animal as TA
ON det.AnimalID=TA.AnimalID
)
INSERT INTO ##ttOrder_det (AnimalID, Technology, XmitID, DD, Location, GLocation, ReceiverID, DetID, PrevDD, BinInc)
SELECT
s1.AnimalID, --was a coalesce
s1.Technology, s1.XmitID, s1.DetectDate, s1.Location, s1.GLocation, s1.ReceiverID,
s1.DetID,
sLAG.DetectDate,
CASE WHEN sLAG.DetectDate IS NULL
THEN 1
ELSE CASE WHEN sLAG.GLocation = s1.GLocation
THEN 0
ELSE 1
END
END AS BinInc
FROM s as s1
LEFT OUTER JOIN s AS sLAG ON
s1.DetID = sLAG.DetID + 1 AND
s1.AnimalID= sLAG.AnimalID --and s.Technology=sLAG.Technology and s.XmitID=sLAG.XmitID;
Wie verschiedene Benutzer (@MartinSmith, @Frisbee) erwähnt oder angedeutet haben, ist die Verwendung von AnimalID
weder der vollständige Primärschlüssel von Tagged_Animal
noch in einer EINZIGARTIGEN Einschränkung definiert. Die Anzahl der Zeilen in der Tabelle A.AnimalID=B.AnimalID AND A.TagSN<B.TagSN
ist jedoch (derzeit) Null. Um diese Abfrage robust zu machen, müsste ich diese Eindeutigkeit erzwingen (oder einfach TagSN von der PK löschen).
Tabellen- und Indexdefinitionen
## ttOrder_det (temporäre Tabelle)
Derzeit werden Indizes erstellt, bevor die Tabelle gefüllt wird. Ich mache Tests durch, bei denen ich die NONCLUSTERED
Nicht- UNIQUE
Index-Erstellung an eine Position verschiebe, nachdem die temporäre Tabelle gefüllt ist.
CREATE TABLE ##ttOrder_det (
AnimalID nvarchar(50) not null,
Technology varchar(25) not null,
XmitID int not null,
DD DateTime not null,
[Location] [nvarchar](255) NULL,
[GLocation] nvarchar(255) NULL,
PrevDD DateTime NULL,
ReceiverID int not null,
DetID int NOT NULL,
BinInc int NULL,
BinNum int NULL,
CONSTRAINT [PK_ttRDA] PRIMARY KEY CLUSTERED
([AnimalID] ASC, [DD] ASC, ReceiverID ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO
CREATE NONCLUSTERED INDEX NIX_F on ##ttOrder_det (AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_VTC ON ##ttOrder_det (ReceiverID ASC, AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_TCD ON ##ttOrder_det (AnimalID ASC, DD ASC);
CREATE NONCLUSTERED INDEX NIX_R ON ##ttOrder_det (DetID ASC);
CREATE NONCLUSTERED INDEX NIX_A ON ##ttOrder_det (GLocation ASC);
CREATE NONCLUSTERED INDEX NIX_DD ON ##ttOrder_det (DD, PrevDD);
CREATE UNIQUE INDEX UX_CTR ON ##ttOrder_det (AnimalID ASC, DetID ASC);
CREATE NONCLUSTERED INDEX NIX_Bi ON ##ttOrder_det (BinInc ASC);
CREATE NONCLUSTERED INDEX NIX_CT ON ##ttOrder_det (XmitID ASC, Technology ASC);
Tagged_Animal
CREATE TABLE [dbo].[Tagged_Animal](
[DateTagged] [datetime] NULL,
[AnimalID] [nvarchar](50) NOT NULL,
[TagSN] [nvarchar](50) NOT NULL,
[XmitID] [int] NULL,
[Technology] [varchar](25) NULL,
[Animal_SubType] [nvarchar](50) NULL,
[Species] [nvarchar](30) NULL,
[StudyID] [nvarchar](50) NULL,
[Weight] [float] NULL,
[Length] [int] NULL,
[Length_Type] [nvarchar](50) NULL,
[Date_Released] [datetime] NULL,
[Release_Location] [nvarchar](50) NULL,
[Lat] [float] NULL,
[Lon] [float] NULL,
[Course_Dist_km] [float] NULL,
[Sex] [nvarchar](255) NULL,
[Life_Stage] [nvarchar](255) NULL,
[Marking_Method] [nvarchar](255) NULL,
[Tag_Type] [varchar](30) NULL,
[Notes] [nvarchar](255) NULL,
CONSTRAINT [PK_tbl_Tagged_Animal] PRIMARY KEY CLUSTERED
(
[AnimalID] ASC,
[TagSN] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [I_TF_TagCode] ON [dbo].[Tagged_Animal]
(
[XmitID] ASC,
[Technology] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Detections_with_Location
CREATE TABLE [dbo].[Detections_with_Location](
[AnimalID] [nvarchar](50) NOT NULL,
[XmitID] [int] NOT NULL,
[Technology] [varchar](25) NOT NULL,
[DetectDate] [datetime] NOT NULL,
[ReceiverID] [int] NOT NULL,
[Data] [float] NULL,
[Units] [varchar](50) NULL,
[Location] [nvarchar](255) NULL,
[StartD] [datetime] NULL,
[StopD] [datetime] NULL,
[fname] [nvarchar](255) NULL,
[notes] [nvarchar](max) NULL,
CONSTRAINT [PK_dlwk] PRIMARY KEY CLUSTERED
(
[ReceiverID] ASC,
[Technology] ASC,
[XmitID] ASC,
[DetectDate] ASC,
[AnimalID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [NIX_VTC] ON [dbo].[Detections_with_Location]
(
[ReceiverID] ASC,
[AnimalID] ASC,
[XmitID] ASC,
[Technology] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [NIX_TCpi] ON [dbo].[Detections_with_Location]
(
[XmitID] ASC,
[Technology] ASC
)
INCLUDE ( [DetectDate],
[ReceiverID],
[Data],
[Units],
[Location]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [NIX_TCD] ON [dbo].[Detections_with_Location]
(
[AnimalID] ASC,
[XmitID] ASC,
[Technology] ASC,
[DetectDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [NIX_F] ON [dbo].[Detections_with_Location]
(
[AnimalID] ASC
)
INCLUDE ( [XmitID],
[Technology],
[DetectDate],
[ReceiverID],
[Data],
[Units],
[Location]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [NIX_DSS] ON [dbo].[Detections_with_Location]
(
[ReceiverID] ASC,
[Location] ASC,
[StartD] ASC,
[StopD] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Receiver_Locations
CREATE TABLE [dbo].[Receiver_Locations](
[Region] [nvarchar](50) NULL,
[Location_Long] [nvarchar](50) NULL,
[Location] [nvarchar](50) NOT NULL,
[Lat] [float] NULL,
[Lon] [float] NULL,
[Altitude] [float] NULL,
[Elevation] [float] NULL,
[RiverKm] [float] NULL,
[LocationType] [nvarchar](50) NULL,
[General_Location] [nvarchar](50) NULL,
[Nearest_Access] [nvarchar](50) NULL,
[Responsible_Agent] [nvarchar](50) NULL,
[Agent_Phone] [nvarchar](255) NULL,
[Agent_Email] [nvarchar](255) NULL,
CONSTRAINT [PK_tbl_Receiver_Locations] PRIMARY KEY CLUSTERED
(
[Location] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Tischgrößen
Tagged_Animals: 10 Tausend
Detections_with_Location: 46+ Millionen Einträge
Receiver_Locations: 800
Spezifische Fehler empfangen
Speicherplatz für Objekt 'dbo.SORT temporärer Ausführungsspeicher: 140737631617024' in Datenbank 'tempdb' konnte nicht zugeordnet werden, da die Dateigruppe 'PRIMARY' voll ist. Erstellen Sie Speicherplatz, indem Sie nicht benötigte Dateien löschen, Objekte in der Dateigruppe löschen, der Dateigruppe zusätzliche Dateien hinzufügen oder das automatische Wachstum für vorhandene Dateien in der Dateigruppe aktivieren.
Das Transaktionsprotokoll für die Datenbank 'tempdb' ist voll. Informationen dazu, warum Speicherplatz im Protokoll nicht wiederverwendet werden kann, finden Sie in der Spalte log_reuse_wait_desc in sys.databases (tempdb ACTIVE_TRANSACTION).
Beim Ausführen des Stapels ist ein Fehler aufgetreten. Die Fehlermeldung lautet: Ausnahme vom Typ 'System.OutOfMemoryException' wurde ausgelöst - (wenn dies
s
als direkte Auswahl nach ungefähr 33 Millionen Datensätzen erfolgt).
(Geschätzter) Ausführungsplan Zusammenfassung des ursprünglichen Codes
INSERT
Kosten 0%
SEQUENCE
Kosten 0%, aber Zeichnen aus 9 verschiedenen Teilschritten. Diese Teilschritte (mit typischen Kosten) sind Index Insert
(2%), gefolgt von Sort
(8%), gefolgt von Table Spool
(2%). NIX_A
hat Kosten von 9% für Index Insert
und weder NIX_TCD
noch NIX_F
einen Sort
Schritt; Das Table Spool
für NIX_F
ist kostenlos.
Die Clustered Index Insert
Kosten betragen 10%.
Es gibt auch Sort
Kosten von 2% und Parallelism
Kosten von 1% für die Verteilung von Streams.
Für die SEQUENCE
Kosten, so scheint es , mit anderen Schritten bis 95%, hinzufügen 13% Kalkulation, so offensichtlich gibt es einige Runden „Fehler“ irgendwo, wahrscheinlich vor allem in dem 14% der Index Insert
- Sort
- Table Spool
Sequenz.
Notizen / Refs
LAG / LEAD-Implementierung basierend auf dem SQL Authority-Blogeintrag
Siehe auch diesen Stackexchange-Thread
Meine Fragen
Irgendwelche Verbesserungsvorschläge?
Kann ich auch partitionieren, wenn ich die Kopien von beitrete
s
?Würden sich die Dinge verbessern, wenn ich
s
eine diskrete temporäre Tabelle erstellen und sie entsprechend indizieren würde?Wäre es effizienter, die Nichtindizes
UNIQUE
in den temporären Tabellen zu erstellen, nachdem alle Einfügungen ausgeführt wurden? Ich gehe davon aus, dass dieUNIQUE
(und damitPRIMARY KEY
) Indizes im Voraus erstellt werden müssen, um Verstöße gegen wichtige Einschränkungen zu verhindern.
Um eine meiner eigenen Fragen zu beantworten
- Ja, ja, das würde es. Nach weiteren Optimierungen
- 21 Minuten, um die temporäre Tabelle mit Daten zu füllen
- 1 Minuten zum Indexieren
Dieser Prozess dauerte zuvor mindestens 1,5 Stunden, war fehlerhaft und ergab keine Ergebnistabelle. Bevor ich anfing, mich mit der Logik der Abfrage zu beschäftigen, dauerte es tatsächlich mehr als 4 Stunden, bis ein Fehler auftrat.
Serverspezifikationen:
Prozessor: Xeon E3-1240 V2 bei 3,4 GHz (4 Core / 8 Thread)
Speicher: 16 GB
Auslagerungsdatei: 16 GB auf 111 GB SSD (52 GB frei)
Tempdb + meine Datenbank auf 223 GB SSD (119 GB frei)
Aktueller Status
Siehe meine gepostete Lösung / Antwort.
cast(det.XmitID AS nvarchar(10)), N'BSVALUE999'
<- denken Sie daran, dass nvarchar ohne Länge und undN
zu einer impliziten Konvertierung führt. Nur eine Kleinigkeit zu beachten. Sie können Pastebin verwenden, um Code zu veröffentlichen und ihn hier zu verlinken.RANK() OVER (PARTITION BY det.Technology, det.XmitID ORDER BY DetectDate ASC, ReceiverID ASC) as DetID
aber dann selbst , wenn Sies1.DetID = sLAG.DetID + 1 AND s1.AnimalID= sLAG.AnimalID
möglicherweise Zeilen aus verschiedenen Partitionen verbinden. Ich würde zuerst die Abfrage korrigieren und dann die Änderung der Indizes untersuchen, um zu vermeiden, dass überhaupt sortiert werden muss. zBCREATE NONCLUSTERED INDEX [NIX_TCpi] ON [dbo].[Detections_with_Location] ( [XmitID] ASC, [Technology] ASC, [DetectDate] ASC, [ReceiverID] ASC ) INCLUDE ( AnimalID, [Data], [Units], [Location])
COALESCE
Anweisung vorhanden ist. Es gibt auch Umstände, unter denen mehrere markierte Tiere das gleicheTechnology
und habenXmitID
, aber die Annahme ist, dass dasAnimalID
im Wesentlichen eine Teilmenge derTechnology
*XmitID
-Kombination ist. Ich würde dasRANK
für dieCOALESCE
Anweisung tun , aber 2008 R2 gibt einen Fehler für dieRANK
Aggregation aus. Zuerst hatte ichs1.AnimalID= sLAG.AnimalID and s.Technology=sLAG.Technology and s.XmitID=sLAG.XmitID
, hatte aber die gleichen Fehler.COALESCE()
ist. Wenn man bedenkt, dass das Ergebnis später für einen Self-Join verwendet wird, ist die Leistung wahrscheinlich beeinträchtigt. Ich habe keine Ahnung, welchen Vorschlag dieses Blogs Sie verwendet haben (die Formatierung in diesem Blog ist schrecklich und das ist nicht die einzige schreckliche Sache, trotz des ausgefallenen Namens), aber ich bin sicher, dass es viele effiziente Möglichkeiten gibt, eine Lücke zu lösen - und -island Problem wie bei Ihnen, ohne Self-Joins für berechnete Spalten zu verwenden.Antworten:
Ich sende dies als Antwort, da ich derzeit die Fehler vom Typ "Nicht genügend Speicher" vermeide und die Laufzeit erheblich verkürzt habe (4+ Stunden, endend mit einem Fehler; jetzt 1,25 Stunden, endend mit Erfolg) ). Ich bin mir jedoch sicher, dass dieses Problem nach etwa 10 Millionen weiteren Datensätzen erneut auftreten kann. Daher würde ich mich über zusätzliche Kommentare oder Antworten freuen, die darauf abzielen, dies für die Zukunft speichereffizienter zu gestalten.
Die "Lösung" für diesen Punkt bestand darin, nicht benötigte Felder und insbesondere Indizes aus dem Entwurf der temporären Tabellen zu entfernen. Darüber hinaus wurde die Indexerstellung für Schlüssel ohne Einschränkungen verschoben, bis die Tabelle gefüllt wurde.
Um das Problem (zuerst von @MartinSmith hervorgehoben) der Partitionierung zu
JOIN
beheben, das nicht mit dem späteren übereinstimmt , habe ich ein Feld in einer Unterabfrage erstellt, das ich dann sowohl fürPARTITION
ing als auch fürJOIN
ing verwendet habe.Code für das Q.
Schnelle Kommentare
Ich wechselte zu
ROW_NUMBER
anstelle vonRANK
. Dies ist nicht deterministisch, führt aber zumindest zu keinen "Bindungen", was zu einem Bruch derLAG
Implementierung um diesen Punkt führen würde. Bindungen sollten nicht existieren, aber dies ist nur eine Zukunftssicherung gegenGeneral_Location
s, die sehr nahe beieinander liegen und dieselbe Übertragung gemeinsam erkennen.Wie zwei Benutzer in den obigen Kommentaren betonten, verwende ich nicht die vollständige PK der
Tagged_Animal
Tabelle, daher besteht die Möglichkeit, dass es eineJOIN
mit einer mehrdeutigen gibtAnimalID
. Gegenwärtig ist jedoch, beideAnimalID
undTagSN
sindUNIQUE
, wenn auch ungezwungen.Ich hatte vor, das
ReceiverID
Feld zugunsten der Nutzung des Feldes fallen zu lassenLocation
, aber ich hatte einen Zeitraum, in dem zwei Empfänger am selben Ort eingesetzt waren (ein Empfänger wurde als verloren angesehen, aber später gefunden), die tatsächlich dasselbe Tier zur selben Zeit entdecktenFolgecode zum Abschließen der Aufgabe
quelle