Lead / Lag-Implementierung in SQL Server 2008 R2: Maximaler Speicher überschritten


7

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 LocationSequenz 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 LAGund LEADist in SQL Server 2008R2 nicht verfügbar (noch ist UNBOUNDED PRECEDINGin der PARTITIONing - 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 AnimalIDweder der vollständige Primärschlüssel von Tagged_Animalnoch in einer EINZIGARTIGEN Einschränkung definiert. Die Anzahl der Zeilen in der Tabelle A.AnimalID=B.AnimalID AND A.TagSN<B.TagSNist 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 NONCLUSTEREDNicht- UNIQUEIndex-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

  1. 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.

  2. 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).

  3. Beim Ausführen des Stapels ist ein Fehler aufgetreten. Die Fehlermeldung lautet: Ausnahme vom Typ 'System.OutOfMemoryException' wurde ausgelöst - (wenn dies sals direkte Auswahl nach ungefähr 33 Millionen Datensätzen erfolgt).

(Geschätzter) Ausführungsplan Zusammenfassung des ursprünglichen Codes

INSERTKosten 0%
SEQUENCEKosten 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_Ahat Kosten von 9% für Index Insertund weder NIX_TCDnoch NIX_Feinen SortSchritt; Das Table Spoolfür NIX_Fist kostenlos.
Die Clustered Index InsertKosten betragen 10%.
Es gibt auch SortKosten von 2% und ParallelismKosten von 1% für die Verteilung von Streams.
Für die SEQUENCEKosten, 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 SpoolSequenz.

Notizen / Refs

LAG / LEAD-Implementierung basierend auf dem SQL Authority-Blogeintrag
Siehe auch diesen Stackexchange-Thread

Meine Fragen

  1. Irgendwelche Verbesserungsvorschläge?

  2. Kann ich auch partitionieren, wenn ich die Kopien von beitrete s?

  3. Würden sich die Dinge verbessern, wenn ich seine diskrete temporäre Tabelle erstellen und sie entsprechend indizieren würde?

  4. Wäre es effizienter, die Nichtindizes UNIQUEin den temporären Tabellen zu erstellen, nachdem alle Einfügungen ausgeführt wurden? Ich gehe davon aus, dass die UNIQUE(und damit PRIMARY KEY) Indizes im Voraus erstellt werden müssen, um Verstöße gegen wichtige Einschränkungen zu verhindern.

Um eine meiner eigenen Fragen zu beantworten

  1. 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.



1
Haben Sie etwas dagegen, auch einige Daten zu veröffentlichen? Es wäre einfach, einen Repro zu erstellen und Ihnen zu helfen. Außerdem sollte die Abfrage cast(det.XmitID AS nvarchar(10)), N'BSVALUE999'<- denken Sie daran, dass nvarchar ohne Länge und und Nzu 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.
Kin Shah

5
Ihre aktuelle Abfrage sieht nicht korrekt aus. Sie tun dies RANK() OVER (PARTITION BY det.Technology, det.XmitID ORDER BY DetectDate ASC, ReceiverID ASC) as DetIDaber dann selbst , wenn Sie s1.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])
Martin Smith

Guter Punkt für die Indizierung. Das Problem ist, dass sich nicht alle markierten Tiere in der Datenbank befinden, weshalb die Verkettung in der COALESCEAnweisung vorhanden ist. Es gibt auch Umstände, unter denen mehrere markierte Tiere das gleiche Technologyund haben XmitID, aber die Annahme ist, dass das AnimalIDim Wesentlichen eine Teilmenge der Technology* XmitID-Kombination ist. Ich würde das RANKfür die COALESCEAnweisung tun , aber 2008 R2 gibt einen Fehler für die RANKAggregation aus. Zuerst hatte ich s1.AnimalID= sLAG.AnimalID and s.Technology=sLAG.Technology and s.XmitID=sLAG.XmitID, hatte aber die gleichen Fehler.
mpag

Sie haben keine Beispieldaten angezeigt. Ich frage mich, was die Notwendigkeit dafür 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.
Ypercubeᵀᴹ

Antworten:


5

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 JOINbeheben, das nicht mit dem späteren übereinstimmt , habe ich ein Feld in einer Unterabfrage erstellt, das ich dann sowohl für PARTITIONing als auch für JOINing verwendet habe.

Code für das Q.

set nocount on;
SET XACT_ABORT ON;
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'started' as reason; --last run 2015-12-16 18:22:02
GO

CREATE TABLE ##ttOrder_det (
    AnimalID nvarchar(50) not null,
    DD DateTime not null,
    ReceiverID int NOT NULL,
    Location nvarchar(255) NOT NULL,
    GLocation nvarchar(255) NULL,
    DetID int NOT NULL,
    BinIncORNum int NULL, -- first pass=Inc, second pass=Num
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 UNIQUE INDEX UX_CTR ON ##ttOrder_det (AnimalID ASC, DetID ASC);
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
   'created first temporary table' as reason;  --last run 2015-12-16 18:22:02
GO
WITH s AS (
    SELECT 
        AnimalID, DetectDate,
        ReceiverID, Location, GLocation,
        ROW_NUMBER() OVER (
            PARTITION BY AnimalID ORDER BY DetectDate ASC, ReceiverID ASC
        ) as DetID
    FROM (
        SELECT 
            COALESCE (
                TF.AnimalID,
                Det.Technology+'-'+cast(Det.XmitID AS nvarchar(10)),
                Det.AnimalID,
                N'BSVALUE999'
            ) as AnimalID,
            DetectDate,
            ReceiverID,
            COALESCE (
                Det.location,
                N'Unknown Location'
            ) as Location,
            COALESCE (
                ML.General_Location,
                N'Invalid General Location - Orphaned Receiver'
            ) as GLocation
        FROM
            Detections_with_Location as Det LEFT OUTER JOIN
            Receiver_Locations as ML ON Det.Location=ML.Location LEFT OUTER JOIN
            Tagged_Animal as TF ON Det.AnimalID=TF.AnimalID
    ) AS T
)
INSERT INTO ##ttOrder_det (AnimalID, DD, ReceiverID, Location, GLocation, DetID, BinIncORNum)
    SELECT 
        s1.AnimalID,
        s1.DetectDate, s1.ReceiverID, s1.Location, s1.GLocation,
        s1.DetID, 
        CASE WHEN sLg.DetectDate IS NULL
            THEN 1 
            ELSE CASE WHEN sLg.GLocation = s1.GLocation
                THEN 0
                ELSE 1
            END
        END AS BinInc
    FROM s as s1
    LEFT OUTER JOIN s AS sLg ON
        s1.AnimalID= sLg.AnimalID AND
        s1.DetID = sLg.DetID + 1
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
   'filled first temp table' as reason,
   COUNT(*) as SizeOfFirstTemp FROM ##ttOrder_det; --2015-12-16 18:43:03, 46627879
GO
CREATE NONCLUSTERED INDEX NIX_F on ##ttOrder_det (AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_R ON ##ttOrder_det (DetID ASC);
--dropped several additional indices: `NIX_`s VTC, TCD, A, DD, Bi
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'indexed first temp table' as reason; --2015-12-16 18:44:12
GO

Schnelle Kommentare

Ich wechselte zu ROW_NUMBERanstelle von RANK. Dies ist nicht deterministisch, führt aber zumindest zu keinen "Bindungen", was zu einem Bruch der LAGImplementierung um diesen Punkt führen würde. Bindungen sollten nicht existieren, aber dies ist nur eine Zukunftssicherung gegen General_Locations, 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_AnimalTabelle, daher besteht die Möglichkeit, dass es eine JOINmit einer mehrdeutigen gibt AnimalID. Gegenwärtig ist jedoch, beide AnimalIDund TagSNsind UNIQUE, wenn auch ungezwungen.

Ich hatte vor, das ReceiverIDFeld zugunsten der Nutzung des Feldes fallen zu lassen Location, 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 entdeckten

Folgecode zum Abschließen der Aufgabe

CREATE TABLE ##ttOrder_det2 (
    AnimalID nvarchar(50) not null,
    DetID int NOT NULL,
    BinNum int NULL,
CONSTRAINT [PK_ttRDA2] PRIMARY KEY CLUSTERED 
    ([AnimalID] ASC, [DetID] 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
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'second temp table created' as reason; --2015-12-16 18:44:15
GO
-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs. 
BEGIN TRANSACTION
  BEGIN TRY
   DECLARE @AnimalID as nvarchar(50);
    DECLARE @DetID as int;
    DECLARE @BinInc as int;
    DECLARE @BinNum as int;
    DECLARE @AnimalVisit as CURSOR;
    SET @AnimalVisit = CURSOR FOR SELECT AnimalID, DetID, BinIncORNum FROM ##ttOrder_det ORDER BY AnimalID, DetID;
    OPEN @AnimalVisit;
    FETCH NEXT FROM @AnimalVisit INTO @AnimalID, @DetID, @BinInc;
    WHILE @@FETCH_STATUS = 0
      BEGIN
        IF (@DetID <= 1) SET @BinNum = 0;
        SET @BinNum += @BinInc;
        INSERT INTO ##ttOrder_det2 (AnimalID, DetID, BinNum) VALUES (@AnimalID, @DetID, @BinNum);
        FETCH NEXT FROM @AnimalVisit INTO @AnimalID, @DetID, @BinInc;
      END
    CLOSE @AnimalVisit;
    DEALLOCATE @AnimalVisit;
  END TRY
  BEGIN CATCH
    exec sp_lock; -- added to display the open locks after the timeout
--    exec sp_who2; -- shows the active processes
    EXECUTE usp_GetErrorInfo;
    --RETURN -- ignoring this error for brevity
        -- Test XACT_STATE:
        -- If 1, the transaction is committable.
        -- If -1, the transaction is uncommittable and should 
        --     be rolled back.
        -- XACT_STATE = 0 means that there is no transaction and
        --     a commit or rollback operation would generate an error.

    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        SELECT
            cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
            'The transaction is in an uncommittable state. Rolling back transaction.' as reason
            SET XACT_ABORT off
            RETURN -- 1 --error
        ROLLBACK TRANSACTION;
    END;
    -- Test whether the transaction is committable.
    IF (XACT_STATE()) = 1
    BEGIN
        SELECT
            cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
            'The transaction is committable. Committing transaction.' as reason
        COMMIT TRANSACTION;   
    END;
  END CATCH;
  IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO
SELECT 
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'filled second temp table' as reason,
    COUNT(*) as Table2Size from ##ttOrder_det2; --2015-12-16 19:11:17, 46627879
GO
CREATE NONCLUSTERED INDEX NIX_CT2 ON ##ttOrder_det2 (AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_R2 ON ##ttOrder_det2 (DetID ASC);
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'indexed second temp table' as reason;
--EXEC tempdb.dbo.usp_PruneTemp;
GO
BEGIN TRANSACTION
    BEGIN TRY
        UPDATE a
            SET a.BinIncORNum=b.BinNum
        FROM ##ttOrder_det AS a
        INNER JOIN ##ttOrder_det2 AS b ON 
            a.AnimalID=b.AnimalID AND a.DetID=b.DetID;
        SELECT
            cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
            'backfilled first temp table with info from second table' as reason,
            @@ROWCOUNT as EntriesAffected;  --2015-12-16 19:19:54, 46627879
        DROP TABLE ##ttOrder_det2;
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        SELECT name, log_reuse_wait_desc FROM sys.databases
        SELECT
          cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
          'ERROR: backfilling first temp table, see sys.databases info' as reason;
        EXECUTE usp_GetErrorInfo;
        IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
        SET XACT_ABORT off
        RETURN --1 --error
    END CATCH
--IF @@TRANCOUNT > 0 COMMIT TRANSACTION
GO
CREATE TABLE derived__AnimalVisits (
    AnimalID nvarchar(50) not null,
    DetectDate DateTime not null,
    ReceiverID int NOT NULL,
    Location nvarchar(255) NOT NULL,
    GeneralLocation nvarchar(255) NULL,
    DetOrder int NOT NULL,
    VisitNum int NOT NULL,
CONSTRAINT [PK_dFV] PRIMARY KEY CLUSTERED 
    (AnimalID ASC, DetectDate 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 UNIQUE INDEX UX_CTR ON derived__AnimalVisits (AnimalID ASC, DetOrder ASC);
SELECT 
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'created persistent derived table' as reason; --2015-12-16 19:20:53
GO

--DECLARE @FVError as int = 0;
BEGIN TRY
    INSERT INTO derived__AnimalVisits (AnimalID, DetectDate, ReceiverID, Location, GeneralLocation, DetOrder, VisitNum)
        SELECT AnimalID, DD, ReceiverID, Location, GLocation, COALESCE(DetID,0), COALESCE(BinIncORNum,0) FROM ##ttOrder_det;
END TRY
BEGIN CATCH
    SELECT
        cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
        'ERROR: filling persistent derived table' as reason;
    EXECUTE usp_GetErrorInfo;
    SET XACT_ABORT off
    RETURN --1 --error
END CATCH
CREATE NONCLUSTERED INDEX NIX_CT ON derived__AnimalVisits (AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_VTC ON derived__AnimalVisits (ReceiverID ASC, AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_TCD ON derived__AnimalVisits (AnimalID ASC, DetectDate ASC);
CREATE NONCLUSTERED INDEX NIX_R ON derived__AnimalVisits (DetOrder ASC);
CREATE NONCLUSTERED INDEX NIX_Bi ON derived__AnimalVisits (VisitNum ASC);
SELECT
    cast(cast(current_timestamp as datetime2) as varchar(19)) as time,
    'indexed / now cleaning up' as reason; --2015-12-16 19:31:18
GO
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[##ttOrder_det2]') AND xtype=N'U')
    DROP TABLE tempdb.[dbo].[##ttOrder_det2];
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = OBJECT_ID(N'[tempdb].[dbo].[##ttOrder_det]') AND xtype=N'U')
    DROP TABLE tempdb.[dbo].[##ttOrder_det];
SET XACT_ABORT off
--cleaning up of transaction logs, etc done at 2015-12-16 19:39:07
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.