2

Ich habe eine Anwendung, die SqlBulkCopy verwendet, um Daten in eine Reihe von Tabellen zu verschieben. Es hat sich kürzlich herausgestellt, dass Benutzer, die SQL2016 verwenden, Probleme melden, wenn ihre Festplatten mit sehr großen Datenbanken gefüllt sind (die nicht so groß sein sollten). Dieses Problem tritt bei SQL2014 nicht auf. Bei der Überprüfung scheint es, dass das Ausführen von TableDataSizes.sql (Skript angefügt) große Mengen an Speicherplatz in UnusedSpaceKB zeigte.Verwenden von SQLBulkCopy - Bedeutend größere Tabellen in SQL Server 2016 als in SQL Server 2014

Ich würde gerne wissen, ob a) Es gibt einen Fehler in SQLServer 2016 oder wenn unsere Verwendung von SQLBulkCopy mit einer neuen Funktion "zusammengestoßen" hat. Ich stelle fest, dass es einige Änderungen bei der Seitenzuordnung in SQL Server 2016 gegeben hat. Im Allgemeinen - Was verursacht das?

Schritte zum Reproduzieren Hinweis - Das Folgende beschreibt eine Situation, die ich mit nicht wesentlichen Informationen entfernt sehe. Ich speichere nicht wirklich Tausende von Zeitstempeln in einer Datenbanktabelle (die anderen Spalten wurden entfernt).

  1. eine Datenbank in SQL erstellen in diesem DB (Mine wurde TestDB genannt)
  2. Erstellen Sie eine Tabelle

    USE [TestDB] 
    GO 
    
    /****** Object: Table [dbo].[2017_11_03_DM_AggregatedPressure_Data] Script Date: 07/11/2017 10:30:36 ******/ 
    SET ANSI_NULLS ON 
    GO 
    
    SET QUOTED_IDENTIFIER ON 
    GO 
    
    CREATE TABLE [dbo].[TestTable](
        [TimeStamp] [datetime] NOT NULL 
    ) ON [PRIMARY] 
    
    GO 
    
  3. Erstellen Sie einen Index für die Tabelle (mit Script (Skript wie unten verwenden) wie folgt)

    USE [TestDB] 
    GO 
    
    /****** Object: Index [2017_11_03_DM_AggregatedPressure_Data_Index] Script Date: 07/11/2017 10:32:44 ******/ 
    CREATE CLUSTERED INDEX [TestTable_Index] ON [dbo].[TestTable] 
    (
        [TimeStamp] ASC 
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
    GO 
    
  4. Starten Sie die Datensätze mit dem unten angegebenen Code in die Tabelle. (Dies ist der Code-behind für ein Windows-Formular, dass einfach eine Taste namens btnGo drauf und eine NumericUpDown genannt nupRecordsToInsert.

    Public Class Form1 
    
    Private conStr As String = "Integrated Security=true;Persist Security Info=true;Server=.;Database=TestDB;Pooling=True" 
    Dim tableName As String = "TestTable" 
    
    Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click 
    
        Dim table as DataTable = GetData(nupRecordsToInsert.Value) 
    
        Using conn As SqlConnection = New SqlConnection(conStr) 
         conn.Open() 
         Using sbc As SqlBulkCopy = New SqlBulkCopy(conStr, SqlBulkCopyOptions.UseInternalTransaction Or SqlBulkCopyOptions.KeepIdentity) 
    
          sbc.DestinationTableName = "[" & tableName & "]" 
          sbc.BatchSize = 1000 
          sbc.WriteToServer(table) 
    
         End Using 
        End Using 
    
        MessageBox.Show($"Records Inserted = {nupRecordsToInsert.Value} into Database - TestDB. Table - {tableName}") 
    End Sub 
    
    Private Function GetData(numOfRecordsNeeded As Integer) As DataTable 
        Dim table As DataTable = New DataTable() 
        table.Columns.Add("TimeStamp", GetType(DateTime)) 
    
        Dim dtDateTimeToInsert as DateTime = DateTime.Now 
    
        For index As Integer = 1 To numOfRecordsNeeded 
         dtDateTimeToInsert = dtDateTimeToInsert.AddSeconds(2) 
         table.Rows.Add(dtDateTimeToInsert) 
        Next 
    
        Return table 
    End Function 
    

    End Class

  5. An einem gewissen Punkt rund 500 erfasst die Anzahl der Elemente in die Datenbanktabelle wird bedeuten, dass neue Datensätze auf eine neue Seite geschrieben werden müssen. an dieser Stelle interessant, dies in Actual Ergebnisse als skizzierte passieren.

Tatsächliche Ergebnisse Die Datenbanken in SQL2016 sind extrem groß (dies geschieht, nachdem die erste Seite gefüllt und eine zweite Seite gestartet wurde).

Dies kann im Detail zu sehen, wenn

  1. die unterhalb SQL Lauf eine Vorstellung von dem tablesizes zu bekommen. Je mehr Datensätze in der Datenbank ausgeführt werden, desto mehr extrem große Zahlen in der Spalte UnusedSpaceKB.

    use [TestDB] 
    
    SELECT 
        t.NAME AS TableName, 
        s.Name AS SchemaName, 
        p.rows AS RowCounts, 
        SUM(a.total_pages) * 8 AS TotalSpaceKB, 
        SUM(a.used_pages) * 8 AS UsedSpaceKB, 
        (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB 
    FROM 
        sys.tables t 
    INNER JOIN  
        sys.indexes i ON t.OBJECT_ID = i.object_id 
    INNER JOIN 
        sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id 
    INNER JOIN 
        sys.allocation_units a ON p.partition_id = a.container_id 
    LEFT OUTER JOIN 
        sys.schemas s ON t.schema_id = s.schema_id 
    WHERE 
        t.NAME = 'TestTable' 
        AND t.is_ms_shipped = 0 
        AND i.OBJECT_ID > 255 
    GROUP BY 
        t.Name, s.Name, p.Rows 
    ORDER BY 
        RowCounts desc 
    

Ausgabe in UnusedSpaceKB große Zahl zeigt

die

enter image description here

  1. die unten stehende Abfrage zeigt Laufen, dass viele Seiten zugeordnet wurden, sondern dass nur die Zuerst wird einer von jedem "Satz von 8" verwendet.Dadurch bleiben die letzten 7 von 8 Seiten ungenutzt und es entsteht viel verschwendeter Platz.

    select * from sys.dm_db_database_page_allocations 
    (DB_id() , object_id('[dbo].[TestTable]') , NULL , NULL , 'DETAILED') 
    

Die unten zeigt einen Teil der Ergebnisse, bei denen die Seitenzuweisungen kontinuierlich nicht laufen.
Showing spaces in database_page_allocations results

Die Datenbanken in SQL2014 zeigen dieses Problem nicht 1. Wenn die entsprechende Abfrage ausgeführt wird (wie oben) haben wir große Werte in der UnusedSpaceKB Spalte nicht sehen. Die andere Abfrage (dh querys - dm_db_database_page_allocations) zeigt, dass viele Seiten zugeordnet wurden, aber jede Seite in der Reihenfolge verwendet wird.

  1. Es gibt keine Lücken - keine Blöcke von 7 unbenutzten Seiten.

Contiguous page allocations

Erwartete Ergebnisse I SQL2016 wie SQL2014 verhalten erwarten würde und nicht sehr große Tabellen erstellen. Insbesondere würde ich erwarten, dass die Seiten zusammenhängend zugewiesen werden und keine 7 Seitenlücken in der Zuordnung haben.

Wenn jemand darüber nachdenkt, warum ich diesen Unterschied sehe, wäre das ungeheuer hilfreich.

+2

Haben Sie überprüft, dass der FillFactor-Server auf beiden Servern identisch ist? Ihr CREATE INDEX gibt es NICHT explizit an, daher wird der Serverstandard verwendet. P.S. Warum erstellen Sie Ihren Index NICHT NACH Ihrer BulkCopy? Wie Sie es jetzt tun, werden Sie nie minimale Protokollierung haben – sepupic

+0

Sie verwenden Massenkopie auf die am wenigsten effiziente Weise möglich - Sie haben einen gruppierten Index für die Tabelle, eine Stapelgröße von 1000 und verwenden Zeilensperren statt Tabellensperren Sie erhalten weiterhin gestreamte Daten, aber die Operation selbst wird vollständig protokolliert. Dies sollte jedoch nicht von SQL Server 2014 geändert werden. Sind die Wiederherstellungsmodelle in beiden Fällen identisch? Wurden benutzerdefinierte Ablaufverfolgungsflags angewendet? (Wie das Ablaufverfolgungsflag 610, das eine minimale Protokollierung für Masseneinfügungen in Tabellen mit gruppierten Indizes ermöglicht)? –

+0

Was sind die Einstellungen für die automatische Vergrößerung der Datenbanken? Wie viele Daten werden verschoben? Was bedeutet "zu groß" überhaupt? Die Schritte in dieser Frage sind zu vage, um ein Problem zu reproduzieren. –

Antwort

-1

Sie müssen use trace flag 692:

Wenn aus irgendeinem Grund, können Sie die Chargengröße ändern oder wenn Sie nicht eine verbesserte Datenladeleistung mit Standard minimal Protokollierungsverhalten sehen, können Sie schnell Einsätze Verhalten in SQL deaktivieren Server 2016 verwendet das Ablaufverfolgungsflag 692 (...). Wir erwarten unter normalen Umständen nicht, dass diese Ablaufverfolgungsflagge für Kunden erforderlich ist.

+0

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/18625000) –