SqlBulkCopy를 사용하여 데이터를 테이블 집합으로 이동시키는 응용 프로그램이 있습니다. 최근 SQL2016을 사용하는 사용자는 하드 드라이브가 매우 큰 데이터베이스로 채워지는 문제를보고하고 있습니다. SQL2014에서는이 문제가 발생하지 않습니다. 검사 결과 TableDataSizes.sql (스크립트가 연결됨)을 실행하면 UnusedSpaceKB에 많은 양의 공간이 있음을 알 수 있습니다.SQLBulkCopy 사용 - SQL Server 2016에서보다 SQL Server 2016에서 훨씬 큰 테이블 2014
나는 a) SQLServer 2016에 버그가 있거나 SQLBulkCopy를 사용하여 새로운 기능이 "충돌"했는지 알고 싶습니다. SQL Server 2016에서 페이지 할당에 몇 가지 변경 사항이 있습니다. 일반적으로이 문제의 원인은 무엇입니까?
재현 방법 주 - 아래에서는 필 요하지 않은 정보가 제거 된 상황을 설명합니다. 나는 실제로 데이터베이스 테이블에 수천 개의 타임 스탬프를 저장하지 않고있다. (다른 컬럼은 제거되었다.)
- (광산를 TestDB를 불렀다)
가 (아래 스크립트를 사용하여) 그 DB에서 테이블을 작성
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
하는 스크립트를 사용하여 해당 테이블에 인덱스를 (만들기 SQL의 데이터베이스를 만듭니다 아래와 같이)
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
아래 제공된 코드를 사용하여 테이블에 레코드를 실행하기 시작하십시오. (이 코드는 윈도우가 단순히에 btnGo라는 버튼을 nupRecordsToInsert라는 numericUpDown을 가지고 형성을위한 뒤에이다. (500)의 주위에 어떤 시점에서
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
최종 클래스
- 항목의 수를 기록 데이터베이스 테이블에 새 레코드가 새 페이지에 기록 될 필요가 있음을 의미합니다. 실제 결과에 설명 된대로 흥미있는이 시점에서 이런 일이.
실제 결과 SQL2016의 데이터베이스가 매우 큽니다 (첫 번째 페이지가 채워지고 두 번째 페이지가 시작된 후에 발생 함). tablesizes의 아이디어를 얻기 위해 아래의 SQL을 실행할 때
이
더 자세히 볼 수 있습니다. 데이터베이스로 실행하는 레코드가 많을수록 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
출력 UnusedSpaceKB의
-
아래 쿼리를 실행
가 많은 페이지가 할당 된 것을 알 수 있지만, 단지 그 모든 '8 세트'중 첫 번째가 사용됩니다.이로 인해 8 페이지 중 마지막 7 페이지가 사용되지 않아 낭비되는 공간이 많이 생깁니다.
select * from sys.dm_db_database_page_allocations (DB_id() , object_id('[dbo].[TestTable]') , NULL , NULL , 'DETAILED')
아래는 페이지 할당이 지속적으로 실행하지 않는 결과의 일부를 보여줍니다. (위와 같이) 해당 쿼리를 실행하는 경우 SQL2014에서
데이터베이스는 우리가 UnusedSpaceKB 열에 큰 값이 표시되지 않는이 문제 1. 표시되지 않습니다.
- 다른 쿼리 (queries - dm_db_database_page_allocations)를 실행하면 많은 페이지가 할당되었지만 각 페이지가 순서대로 사용 중임을 알 수 있습니다. 공백이 없습니다. 7 개의 사용되지 않는 페이지가 없습니다. 내가 SQL2016를 기대
예상 결과는 SQL2014처럼 행동하고 매우 큰 테이블을 생성 할 수 있습니다. 특히 나는 페이지가 연속적으로 할당되고 할당에서 7 페이지의 간격을 가지지 않을 것으로 기대합니다.
누구나 내가이 차이점을 보았을 때 어떤 생각을 가지고 있다면 대단히 도움이 될 것입니다.
서버 FillFactor가 두 서버에서 모두 동일한 지 확인 했습니까? CREATE INDEX는이를 명시 적으로 지정하지 않으므로 server default가 사용됩니다. 추신 BulkCopy 이후에 색인을 만들면 어떻습니까? 이제는 최소한의 로깅을 사용하지 않을 것입니다. – sepupic
가장 효율적인 방법으로 대량 복사를 사용하고 있습니다. 테이블에 클러스터 된 인덱스가 있으며 배치 크기가 1000이고 행 잠금이 아닌 테이블 잠금 장치. 스트리밍 된 데이터는 계속 가져 오지만 작업 자체는 완전히 기록됩니다. 그러나 그 자체는 SQL Server 2014에서 변경하면 안됩니다. 두 경우 모두 복구 모델이 동일합니까? 사용자 지정 추적 플래그가 적용 되었습니까? (클러스터 된 인덱스가있는 테이블에서 대량 삽입에 대한 최소 로깅을 가능하게하는 추적 플래그 610과 유사합니까?) –
데이터베이스의 자동 증가 설정은 무엇입니까? 얼마나 많은 데이터가 이동됩니까? '너무 큽니다'는 무엇을 의미합니까? 이 질문의 단계는 너무 모호하여 문제를 재현 할 수 없습니다. –