ความพยายามในการเรียกคืนพื้นที่ที่ไม่ได้ใช้ทำให้พื้นที่ใช้งานเพิ่มขึ้นอย่างมากใน SQL Server


15

ฉันมีตารางในฐานข้อมูลการผลิตที่มีขนาด 525 GB ซึ่งไม่ได้ใช้ 383 GB:

พื้นที่ที่ไม่ได้ใช้

ฉันต้องการเรียกคืนพื้นที่บางส่วนนี้ แต่ก่อนที่จะยุ่งกับฐานข้อมูลการผลิตฉันกำลังทดสอบกลยุทธ์บางอย่างในตารางที่เหมือนกันในฐานข้อมูลทดสอบที่มีข้อมูลน้อยลง ตารางนี้มีปัญหาที่คล้ายกัน:

พื้นที่ที่ไม่ได้ใช้

ข้อมูลบางอย่างเกี่ยวกับตาราง:

  • ปัจจัยเติมถูกตั้งค่าเป็น 0
  • มีประมาณ 30 คอลัมน์
  • หนึ่งในคอลัมน์คือ LOB ของรูปภาพประเภทและมันจัดเก็บไฟล์ที่มีขนาดตั้งแต่ไม่กี่ KB ถึงหลายร้อย MB
  • ตารางนี้ไม่มีดัชนีสมมุติฐานที่เกี่ยวข้อง

เซิร์ฟเวอร์กำลังเรียกใช้ SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64) ฐานข้อมูลใช้SIMPLEโมเดลการกู้คืน

บางสิ่งที่ฉันได้ลอง:

  • ALTER INDEX ALL ON dbo.MyTable REBUILDสร้างใหม่ดัชนี: สิ่งนี้มีผลกระทบเล็กน้อย
  • ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)จัดระเบียบดัชนี: สิ่งนี้มีผลกระทบเล็กน้อย
  • คัดลอกคอลัมน์ LOB ไปยังอีกตารางหนึ่งทิ้งคอลัมน์สร้างคอลัมน์ขึ้นใหม่และคัดลอกข้อมูลกลับมา (ดังที่อธิบายไว้ในโพสต์นี้: การเพิ่มพื้นที่เซิร์ฟเวอร์ SQL ที่ไม่ได้ใช้พื้นที่ว่าง ) สิ่งนี้ลดพื้นที่ที่ไม่ได้ใช้ แต่ดูเหมือนว่าจะแปลงเป็นพื้นที่ใช้แล้ว:

    พื้นที่ที่ไม่ได้ใช้

  • ใช้ยูทิลิตี bcp เพื่อส่งออกตารางตัดและโหลดใหม่ (ดังที่อธิบายไว้ในโพสต์นี้: วิธีเพิ่มพื้นที่ว่างที่ไม่ได้ใช้สำหรับตาราง ) สิ่งนี้ยังช่วยลดพื้นที่ที่ไม่ได้ใช้และเพิ่มพื้นที่ใช้งานในระดับที่ใกล้เคียงกับภาพด้านบน

  • แม้ว่าจะไม่แนะนำ แต่ฉันลองใช้คำสั่ง DBCC SHRINKFILE และ DBCC SHRINKDATABASE แต่พวกเขาไม่ได้มีผลกระทบกับพื้นที่ที่ไม่ได้ใช้
  • การวิ่งDBCC CLEANTABLE('myDB', 'dbo.myTable')ไม่ได้สร้างความแตกต่าง
  • ฉันได้ลองข้างต้นทั้งหมดแล้วในขณะที่ยังคงรักษาประเภทข้อมูลรูปภาพและข้อความและหลังจากเปลี่ยนประเภทข้อมูลเป็น varbinary (สูงสุด) และ varchar (สูงสุด)
  • ฉันพยายามนำเข้าข้อมูลไปยังตารางใหม่ในฐานข้อมูลใหม่และนี่เป็นการแปลงพื้นที่ที่ไม่ได้ใช้เป็นพื้นที่ใช้แล้วเท่านั้น ฉันระบุรายละเอียดของความพยายามนี้ในโพสต์นี้

ฉันไม่ต้องการใช้ความพยายามเหล่านี้กับฐานข้อมูลการผลิตหากสิ่งเหล่านี้เป็นผลลัพธ์ที่ฉันคาดได้ดังนั้น:

  1. ทำไมพื้นที่ที่ไม่ได้ใช้เพิ่งถูกแปลงเป็นพื้นที่ที่ใช้หลังจากความพยายามเหล่านี้แล้ว ฉันรู้สึกว่าฉันไม่มีความเข้าใจที่ดีว่าเกิดอะไรขึ้นภายใต้ประทุน
  2. มีอะไรอีกบ้างที่ฉันสามารถทำได้เพื่อลดพื้นที่ที่ไม่ได้ใช้โดยไม่เพิ่มพื้นที่ใช้งานหรือไม่

แก้ไข: นี่คือรายงานการใช้ดิสก์และสคริปต์สำหรับตาราง:

การใช้งานดิสก์

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable](
    [Column1]  [int] NOT NULL,
    [Column2]  [int] NOT NULL,
    [Column3]  [int] NOT NULL,
    [Column4]  [bit] NOT NULL,
    [Column5]  [tinyint] NOT NULL,
    [Column6]  [datetime] NULL,
    [Column7]  [int] NOT NULL,
    [Column8]  [varchar](100) NULL,
    [Column9]  [varchar](256) NULL,
    [Column10] [int] NULL,
    [Column11] [image] NULL,
    [Column12] [text] NULL,
    [Column13] [varchar](100) NULL,
    [Column14] [varchar](6) NULL,
    [Column15] [int] NOT NULL,
    [Column16] [bit] NOT NULL,
    [Column17] [datetime] NULL,
    [Column18] [varchar](50) NULL,
    [Column19] [varchar](50) NULL,
    [Column20] [varchar](60) NULL,
    [Column21] [varchar](20) NULL,
    [Column22] [varchar](120) NULL,
    [Column23] [varchar](4) NULL,
    [Column24] [varchar](75) NULL,
    [Column25] [char](1) NULL,
    [Column26] [varchar](50) NULL,
    [Column27] [varchar](128) NULL,
    [Column28] [varchar](50) NULL,
    [Column29] [int] NULL,
    [Column30] [text] NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [Column1] ASC,
    [Column2] ASC,
    [Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column4]  DEFAULT (0) FOR [Column4]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column5]  DEFAULT (0) FOR [Column5]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column15]  DEFAULT (0) FOR [Column15]
GO
ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column16]  DEFAULT (0) FOR [Column16]
GO

นี่คือผลลัพธ์ของการดำเนินการคำสั่งในคำตอบของ Max Vernon:

╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
 TotalBytes  FreeBytes  TotalPages  TotalEmptyPages  PageBytesFreePercent  UnusedPagesPercent 
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
  9014280192 8653594624     1100376          997178             95.998700           90.621500 
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
 ObjectName   ReservedPageCount       UsedPageCount 
╠═════════════╬═══════════════════╬════════════════════╣
 dbo.MyTable            5109090             2850245 
╚═════════════╩═══════════════════╩════════════════════╝

UPDATE:

ฉันวิ่งตามดังต่อไปนี้ที่ Max Vernon แนะนำ:

DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');

และนี่คือผลลัพธ์:

DBCC UPDATEUSAGE: Usage counts updated for table 'MyTable' (index 'PK_MyTable', partition 1):
        USED pages (LOB Data): changed from (568025) to (1019641) pages.
        RSVD pages (LOB Data): changed from (1019761) to (1019763) pages.

นี่เป็นการปรับปรุงการใช้งานดิสก์สำหรับตาราง:

ป้อนคำอธิบายรูปภาพที่นี่

และการใช้งานดิสก์โดยรวม:

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นดูเหมือนว่าปัญหาคือการใช้งานดิสก์ที่ติดตามโดย SQL Server กลายเป็นไม่ตรงกับการใช้งานจริงของดิสก์ ฉันจะพิจารณาปัญหานี้แก้ไขได้ แต่ฉันสนใจที่จะรู้ว่าทำไมสิ่งนี้จะเกิดขึ้นตั้งแต่แรก!

คำตอบ:


10

ฉันรันDBCC UPDATEUSAGEกับตารางเป็นขั้นตอนแรกเนื่องจากอาการแสดงการใช้พื้นที่ที่ไม่สอดคล้องกัน

DBCC UPDATEUSAGE แก้ไขแถวหน้าที่ใช้หน้าที่สงวนไว้หน้าใบไม้และหน้าข้อมูลสำหรับแต่ละพาร์ติชันในตารางหรือดัชนี ถ้าไม่มีความไม่ถูกต้องในตารางระบบ DBDD UPUSATEAGE จะไม่ส่งคืนข้อมูล หากพบความไม่ถูกต้องและถูกแก้ไขและไม่ได้ใช้ WITH NO_INFOMSGS DBCC UPDATEUSAGE จะส่งกลับแถวและคอลัมน์ที่มีการอัปเดตในตารางระบบ

ไวยากรณ์คือ:

DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');

หลังจากที่คุณเรียกใช้แล้วฉันจะเรียกใช้EXEC sys.sp_spaceusedกับตาราง:

EXEC sys.sp_spaceused @objname = N'dbo.MyTable'
    , @updateusage = 'false' --true or false
    , @mode = 'ALL' --ALL, LOCAL_ONLY, REMOTE_ONLY
    , @oneresultset = 1;

คำสั่งดังกล่าวมีตัวเลือกในการอัปเดตการใช้งาน แต่เนื่องจากคุณรันDBCC UPDATEUSAGEด้วยตนเองก่อนให้ปล่อยให้ชุดนั้นเป็นเท็จ การเรียกใช้DBCC UPDATEUSAGEด้วยตนเองช่วยให้คุณดูว่ามีอะไรที่แก้ไขหรือไม่

แบบสอบถามต่อไปนี้ควรแสดงเปอร์เซ็นต์ของไบต์ที่ว่างในตารางและเปอร์เซ็นต์ของเพจที่ว่างในตาราง เนื่องจากแบบสอบถามใช้คุณลักษณะที่ไม่มีเอกสารจึงไม่ฉลาดพอที่จะนับรวมกับผลลัพธ์ แต่ดูเหมือนแม่นยำเมื่อเปรียบเทียบกับผลลัพธ์จากsys.sp_spaceusedในระดับสูง

หากเปอร์เซ็นต์ของไบต์ว่างสูงกว่าเปอร์เซ็นต์ของหน้าว่างอย่างมีนัยสำคัญแสดงว่าคุณมีหน้าว่างบางส่วนจำนวนมาก

หน้าว่างบางส่วนสามารถเกิดจากสาเหตุหลายประการ ได้แก่ :

  1. การแบ่งหน้าซึ่งหน้าจะต้องแบ่งเพื่อรองรับการแทรกใหม่ลงในดัชนีคลัสเตอร์

  2. ไม่สามารถเติมหน้าเว็บด้วยคอลัมน์เนื่องจากขนาดคอลัมน์

แบบสอบถามใช้sys.dm_db_database_page_allocationsฟังก์ชันการจัดการแบบไดนามิกที่ไม่มีเอกสาร:

;WITH dpa AS 
(
    SELECT dpa.*
        , page_free_space_percent_corrected = 
          CASE COALESCE(dpa.page_type_desc, N'')
            WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            ELSE COALESCE(dpa.page_free_space_percent, 100)
          END
    FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
)
, src AS
(
SELECT TotalKB = COUNT_BIG(1) * 8192 / 1024
    , FreeKB = SUM((dpa.page_free_space_percent_corrected / 100) * CONVERT(bigint, 8192)) / 1024
    , TotalPages = COUNT_BIG(1)
    , TotalEmptyPages = SUM(CASE WHEN dpa.page_free_space_percent_corrected = 100 THEN 1 ELSE 0 END) --completely empty pages
FROM dpa
)
SELECT *
    , BytesFreePercent = (CONVERT(decimal(38,2), src.FreeKB) / src.TotalKB) * 100
    , UnusedPagesPercent = (CONVERT(decimal(38,2), src.TotalEmptyPages) / src.TotalPages) * 100
FROM src

ผลลัพธ์ดูเหมือนว่า:

╔═════════╦════════╦════════════╦═════════════════ ╦══════════════════╦════════════════════╗
║ TotalKB ║ FreeKB ║ TotalPages ║ TotalEmptyPages ║ BytesFreePercent ║ UnusedPagesPercent ║
╠═════════╬════════╬════════════╬═════════════════ ╬══════════════════╬════════════════════╣
║ 208 ║ 96 ║ 26 ║ 12 ║ 46.153800 ║ 46.153800 ║
╚═════════╩════════╩════════════╩═════════════════ ╩══════════════════╩════════════════════╝

ผมเขียนบล็อกโพสต์อธิบายฟังก์ชั่นที่นี่

ในสถานการณ์ของคุณเมื่อคุณได้ดำเนินการALTER TABLE ... REBUILDคุณจะเห็นจำนวนน้อยมากTotalEmptyPagesแต่ฉันคาดเดาคุณจะยังคงมีประมาณ 72% BytesFreePercentใน

ฉันใช้CREATE TABLEสคริปต์ของคุณเพื่อพยายามสร้างสถานการณ์ของคุณใหม่

นี่คือMCVE ที่ฉันใช้:

DROP TABLE IF EXISTS dbo.MyTable;

CREATE TABLE [dbo].[MyTable](
    [Column1]  [int]            NOT NULL IDENTITY(1,1),
    [Column2]  [int]            NOT NULL,
    [Column3]  [int]            NOT NULL,
    [Column4]  [bit]            NOT NULL,
    [Column5]  [tinyint]        NOT NULL,
    [Column6]  [datetime]       NULL,
    [Column7]  [int]            NOT NULL,
    [Column8]  [varchar](100)   NULL,
    [Column9]  [varchar](256)   NULL,
    [Column10] [int]            NULL,
    [Column11] [image]          NULL,
    [Column12] [text]           NULL,
    [Column13] [varchar](100)   NULL,
    [Column14] [varchar](6)     NULL,
    [Column15] [int]            NOT NULL,
    [Column16] [bit]            NOT NULL,
    [Column17] [datetime]       NULL,
    [Column18] [varchar](50)    NULL,
    [Column19] [varchar](50)    NULL,
    [Column20] [varchar](60)    NULL,
    [Column21] [varchar](20)    NULL,
    [Column22] [varchar](120)   NULL,
    [Column23] [varchar](4)     NULL,
    [Column24] [varchar](75)    NULL,
    [Column25] [char](1)        NULL,
    [Column26] [varchar](50)    NULL,
    [Column27] [varchar](128)   NULL,
    [Column28] [varchar](50)    NULL,
    [Column29] [int]            NULL,
    [Column30] [text]           NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [Column1] ASC,
    [Column2] ASC,
    [Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column4]  DEFAULT (0) FOR [Column4]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column5]  DEFAULT (0) FOR [Column5]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column15]  DEFAULT (0) FOR [Column15]

ALTER TABLE [dbo].[MyTable] ADD  CONSTRAINT [DF_Column16]  DEFAULT (0) FOR [Column16]
GO

INSERT INTO dbo.MyTable (
      Column2
    , Column3
    , Column4
    , Column5
    , Column6
    , Column7
    , Column8
    , Column9
    , Column10
    , Column11
    , Column12
    , Column13
    , Column14
    , Column15
    , Column16
    , Column17
    , Column18
    , Column19
    , Column20
    , Column21
    , Column22
    , Column23
    , Column24
    , Column25
    , Column26
    , Column27
    , Column28
    , Column29
    , Column30
)
VALUES (
          0
        , 0
        , 0
        , 0
        , '2019-07-09 00:00:00'
        , 1
        , REPLICATE('A', 50)    
        , REPLICATE('B', 128)   
        , 0
        , REPLICATE(CONVERT(varchar(max), 'a'), 1)
        , REPLICATE(CONVERT(varchar(max), 'b'), 9000)
        , REPLICATE('C', 50)    
        , REPLICATE('D', 3)     
        , 0
        , 0
        , '2019-07-10 00:00:00'
        , REPLICATE('E', 25)    
        , REPLICATE('F', 25)    
        , REPLICATE('G', 30)    
        , REPLICATE('H', 10)    
        , REPLICATE('I', 120)   
        , REPLICATE('J', 4)     
        , REPLICATE('K', 75)    
        , 'L'       
        , REPLICATE('M', 50)    
        , REPLICATE('N', 128)   
        , REPLICATE('O', 50)    
        , 0
        , REPLICATE(CONVERT(varchar(max), 'c'), 90000)
);
--GO 100

;WITH dpa AS 
(
    SELECT dpa.*
        , page_free_space_percent_corrected = 
          CASE COALESCE(dpa.page_type_desc, N'')
            WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
            ELSE COALESCE(dpa.page_free_space_percent, 100)
          END
    FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
)
, src AS
(
SELECT TotalKB = COUNT_BIG(1) * 8192 / 1024
    , FreeKB = SUM((dpa.page_free_space_percent_corrected / 100) * CONVERT(bigint, 8192)) / 1024
    , TotalPages = COUNT_BIG(1)
    , TotalEmptyPages = SUM(CASE WHEN dpa.page_free_space_percent_corrected = 100 THEN 1 ELSE 0 END) --completely empty pages
FROM dpa
)
SELECT *
    , BytesFreePercent = (CONVERT(decimal(38,2), src.FreeKB) / src.TotalKB) * 100
    , UnusedPagesPercent = (CONVERT(decimal(38,2), src.TotalEmptyPages) / src.TotalPages) * 100
FROM src

แบบสอบถามต่อไปนี้แสดงบรรทัดเดียวสำหรับแต่ละหน้าที่จัดสรรให้กับตารางและใช้ DMV ที่ไม่มีเอกสารเดียวกันนั้น:

SELECT DatabaseName = d.name
    , ObjectName = o.name
    , IndexName = i.name
    , PartitionID = dpa.partition_id
    , dpa.allocation_unit_type_desc
    , dpa.allocated_page_file_id
    , dpa.allocated_page_page_id
    , dpa.is_allocated
    , dpa.page_free_space_percent --this seems unreliable
    , page_free_space_percent_corrected = 
        CASE COALESCE(dpa.page_type_desc, N'')
        WHEN N'TEXT_MIX_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
        WHEN N'TEXT_TREE_PAGE' THEN 100 - COALESCE(dpa.page_free_space_percent, 100)
        ELSE COALESCE(dpa.page_free_space_percent, 100)
        END
    , dpa.page_type_desc
    , dpa.is_page_compressed
    , dpa.has_ghost_records
FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('dbo.MyTable'), NULL, NULL, 'DETAILED') dpa
    LEFT JOIN sys.databases d ON dpa.database_id = d.database_id
    LEFT JOIN sys.objects o ON dpa.object_id = o.object_id
    LEFT JOIN sys.indexes i ON dpa.object_id = i.object_id AND dpa.index_id = i.index_id
WHERE dpa.database_id = DB_ID() --sanity check for sys.objects and sys.indexes

ผลลัพธ์จะแสดงแถวจำนวนมากถ้าคุณเรียกใช้กับตารางจริงของคุณในสภาพแวดล้อมการทดสอบของคุณ แต่มันอาจช่วยให้คุณเห็นว่าปัญหาอยู่ที่ไหน

คุณสามารถเรียกใช้สคริปต์ต่อไปนี้และโพสต์ผลลัพธ์ในคำถามของคุณ? ฉันแค่พยายามทำให้แน่ใจว่าเราอยู่ในหน้าเดียวกัน

SELECT ObjectName = s.name + N'.' + o.name
    , ReservedPageCount = SUM(dps.reserved_page_count)
    , UsePageCount = SUM(dps.used_page_count)
FROM sys.schemas s
    INNER JOIN sys.objects o ON s.schema_id = o.schema_id
    INNER JOIN sys.partitions p ON o.object_id = p.object_id
    INNER JOIN sys.dm_db_partition_stats dps ON p.object_id = dps.object_id
WHERE s.name = N'dbo'
    AND o.name = N'MyTable'
GROUP BY s.name + N'.' + o.name;

2
การรันDBCC UPDATEUSAGEการอัปเดตพื้นที่ที่ไม่ได้ใช้และจำนวนหน้าที่ไม่ได้ใช้ ดูเหมือนว่าการใช้งานดิสก์และข้อมูลหน้าเว็บที่รายงานโดย SQL Server นั้นขาดการซิงค์อย่างมาก - ฉันอัพเดตโพสต์ด้วยรายละเอียด ฉันอยากรู้ว่าเรื่องนี้จะเกิดขึ้นได้อย่างไรในตอนแรก แต่อย่างน้อยก็พบปัญหา ขอบคุณสำหรับความช่วยเหลือของคุณฉันขอขอบคุณจริงๆ!
เคน

0

หนึ่งในคอลัมน์คือ LOB ของรูปภาพประเภทและมันจัดเก็บไฟล์ที่มีขนาดตั้งแต่ไม่กี่ KB ถึงหลายร้อย MB

คุณอาจประสบปัญหาการแตกแฟรกเมนต์ภายใน
การกระจายตัวของหน้าสำหรับตารางนี้คืออะไร
และการกระจายตัวของแถวในแตกต่างจากหน้าปิดแถวหรือไม่?

คุณบอกว่าคุณมีไฟล์ที่มีไม่กี่ KB
SQL Server เก็บทุกอย่างในหน้า 8060 ไบต์ หมายความว่าหากคุณมีแถว (หรือข้อมูลแถว) ที่มีขนาด 4040 ไบต์และอันถัดไปนั้นคล้ายคลึงกันจะไม่พอดีกับทั้งสองในหน้าเดียวกันและคุณจะเสียพื้นที่ครึ่งหนึ่ง ลองเปลี่ยนขนาดแถวของคุณโดยจัดเก็บคอลัมน์ความยาวผันแปร (เริ่มต้นด้วยรูปภาพ) ในตารางอื่น


ฉันไม่คิดว่าการแยกส่วนเป็นปัญหา หลังจากสร้างดัชนีขึ้นใหม่การแตกแฟรกเมนต์สำหรับดัชนีคลัสเตอร์คือ 0.45% และความสมบูรณ์ของหน้าคือ 98.93%
เคน

การสร้างตารางหรือดัชนีขึ้นใหม่จะไม่ช่วยถ้าคุณประสบปัญหาแถวใหญ่หรือข้อมูล LOB ที่ไม่พอดีกับหน้าเว็บขนาด 8KB นี่คือสิ่งที่ Max Vernon อธิบายในรายละเอียดเพิ่มเติม: "คุณมีหน้าว่างบางส่วนจำนวนมาก" หรือที่เรียกว่าการกระจายตัวภายใน
DrTrunks Bell

-3

ฐานข้อมูลอยู่ในโหมดการกู้คืนเต็มหรือไม่? ถ้าเป็นเช่นนั้นเมื่อคุณทำการย่อขนาดมันจะบันทึกการเปลี่ยนแปลงทั้งหมดและจะไม่ย่อขนาดตามที่คุณคาดหวัง ขึ้นอยู่กับเวลาทำการของคุณคุณสามารถสำรองข้อมูลเปลี่ยนเป็นโหมดกู้คืนการจัดส่งจำนวนมากจากนั้นเรียกใช้การย่อขนาดไฟล์ข้อมูล หลังจากนั้นคุณต้องการเรียกใช้สคริปต์ดัชนีเพื่อซ่อมแซม / สร้างใหม่และสลับกลับเป็นการกู้คืนแบบเต็ม นั่นคือสิ่งที่ฉันจะลองต่อไป แต่อีกครั้งมันขึ้นอยู่กับชั่วโมงการทำงานของคุณสำหรับสิ่งทั้งหมดนี้


4
นำรูปแบบการกู้คืนที่น่าสนใจ ฉันคิดว่ามันจะใช้งานได้มากกว่าถ้า OP มีปัญหากับขนาดของล็อกไฟล์ เนื่องจากมันมีปัญหากับขนาดของไฟล์ข้อมูลดังนั้นฉันจะแปลกใจถ้าแบบจำลองการกู้คืนก่อให้เกิดปัญหาที่อธิบายไว้
Josh Darnell

จริง แต่ครั้งเดียวที่ฉันเรียกใช้การลดขนาดและมันไม่ได้ส่งผลกระทบต่อพื้นที่จริง ๆ เพราะของแบบจำลองการกู้คืนดังนั้นฉันคิดว่ามันคุ้มค่าที่นำขึ้นมาในกรณีที่มันวินิจฉัยผิดพลาด
John-Henry Lochbaum

-3

ครั้งเดียวที่ฉันไม่สามารถลดขนาดฐานข้อมูลและเรียกคืนพื้นที่ได้เนื่องจากคุณไม่สามารถลดขนาดฐานข้อมูลเกินขนาดเริ่มต้นของฐานข้อมูลเมื่อมันถูกสร้างขึ้น ตัวอย่างเช่นหากฐานข้อมูลของคุณเป็นสำเนาฐานข้อมูลการผลิตและคุณสร้างฐานข้อมูลครั้งแรกที่ 525GB เซิร์ฟเวอร์ sql จะไม่อนุญาตให้คุณลดขนาดต่ำกว่า 525GB ไม่ว่าคุณจะลบข้อมูลออกจากฐานข้อมูลเท่าใดก็ตาม แต่ถ้าฐานข้อมูลถูกสร้างต่ำกว่า 383GB และเพิ่มขึ้นเป็น 525GB คุณไม่ควรมีปัญหาในการเรียกคืนพื้นที่ ฉันคิดมานานแล้วว่านี่เป็นข้อ จำกัด ที่โง่และไร้เหตุผลโดย Microsoft

ย่อขนาดฐานข้อมูลจนถึงขนาดเริ่มต้นเท่านั้นซึ่งถูกตั้งค่าหลังจากสร้างฐานข้อมูล


คำถามไม่ได้เกี่ยวกับการลดขนาดฐานข้อมูล (และถ้าเป็นไปได้ความสามารถในการลดขนาดนั้นขึ้นอยู่กับพื้นที่ที่ใช้หลังจากพื้นที่ขนาดเริ่มต้น)
52519

ตราบใดที่มีพื้นที่ที่ไม่ได้ใช้เป็นไปได้ที่จะลดขนาดฐานข้อมูลให้เหลือเพียงไม่กี่ MB โดยไม่คำนึงถึงขนาดดั้งเดิม มันไม่จำเป็นต้องเป็นความคิดที่ดี แต่ฉันมีหลายครั้งที่จะลดขนาดฐานข้อมูลและไม่เคยมีข้อ จำกัด เช่นนี้
เรย์

-3

ฉันพบปัญหานี้มาก่อนในกล่องผลิตสิ่งที่คุณต้องทำคือสร้างตารางและดัชนีสำหรับแต่ละตารางใหม่ (ตามลำดับ)

นี่คือแบบสอบถามที่ฉันใช้เพื่อตรวจสอบตาราง มันจะช่วยให้คุณกำหนดว่าต้องสร้างตารางใดและสร้างคิวรี SQL ที่คุณต้องการเรียกใช้ ข้อความค้นหานี้ จำกัด เฉพาะที่มีพื้นที่ว่างที่ไม่ได้ใช้สูงกว่า 1MB และอัตราส่วนที่ไม่ได้ใช้ 5% ดังนั้นคุณจะต้องสร้างเฉพาะสิ่งที่คุณต้องให้ความสำคัญ:

SELECT  'alter table [' + t.NAME + '] rebuild;' AS SQL1, 'alter index all on [' + t.NAME + '] rebuild;' as SQL2, t.NAME AS TableName, p.rows AS RowCounts, SUM(a.total_pages) * 8/1024 AS TotalSpaceMB,  SUM(a.used_pages) * 8/1024 AS UsedSpaceMB,  (SUM(a.total_pages) - SUM(a.used_pages)) * 8/1024 AS UnusedSpaceMB, case when SUM(a.total_pages)=0 then 0 else (SUM(a.total_pages) - SUM(a.used_pages))*100/SUM(a.total_pages) end as Ratio  FROM     sys.tables t (nolock) INNER JOIN       sys.indexes i (nolock)  ON t.OBJECT_ID = i.object_id INNER JOIN  sys.partitions p (nolock) ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id INNER JOIN  sys.allocation_units a (nolock) ON p.partition_id = a.container_id LEFT OUTER JOIN  sys.schemas s (nolock) ON t.schema_id = s.schema_id WHERE  t.is_ms_shipped = 0 AND i.OBJECT_ID > 255  GROUP BY  t.Name, s.Name, p.Rows  
having  (SUM(a.total_pages) - SUM(a.used_pages)) * 8/1024>1
and (SUM(a.total_pages) - SUM(a.used_pages))*100/SUM(a.total_pages)>5
ORDER BY    5 desc

การสร้างตารางขึ้นใหม่ในขณะที่ OP ระบุไว้พวกเขาจะกำจัดการกระจายตัวส่วนใหญ่ ฉันสงสัยว่าการสร้างใหม่จะช่วยเพิ่มเติม
Max Vernon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.