รับขนาดของตารางทั้งหมดในฐานข้อมูล


1271

ฉันได้รับมรดกฐานข้อมูล SQL Server ที่ค่อนข้างใหญ่ ดูเหมือนว่าจะใช้พื้นที่มากเกินกว่าที่ฉันคาดไว้เนื่องจากข้อมูลมีอยู่

มีวิธีง่าย ๆ ในการกำหนดเนื้อที่บนดิสก์ในแต่ละตารางที่ใช้ไปหรือไม่


บทบาทใดที่คุณสามารถเข้าถึงได้ คุณเป็น DBA หรือมีการจัดการผ่านเว็บโฮสต์ลูกค้าหรือสิ่งอื่นที่คล้ายคลึงกันใช่หรือไม่
Rob Allen

อาจเป็นไปได้ที่ซ้ำกันของขนาดตารางและดัชนีใน SQL Server
Joe Stefanelli

@RobAllen ฉันมีสิทธิ์เข้าถึงฐานข้อมูลได้อย่างเต็มที่ดังนั้นสคริปต์ที่ต้องการบทบาทใด ๆ ก็เพียงพอแล้ว
Eric


สำหรับ Azure ฉันใช้สิ่งนี้
Irf

คำตอบ:


2593
SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows,
    SUM(a.total_pages) * 8 AS TotalSpaceKB, 
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB,
    SUM(a.used_pages) * 8 AS UsedSpaceKB, 
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS UsedSpaceMB, 
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSpaceMB
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 NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    TotalSpaceMB DESC, t.Name

7
คำถามที่โง่ แต่เป็นไปได้ไหมที่แบบสอบถามนี้อาจทำให้เกิดการล็อกแถว
GEMI

7
ดัชนีใช้พื้นที่เช่นกันและจำนวนพื้นที่ที่ดัชนีใช้สามารถพบได้กับแบบสอบถามนี้ด้านล่าง
Jens Frandsen

6
สคริปต์ของคุณมีปัญหากับดัชนีที่กรอง: สำหรับแต่ละดัชนีที่กรองสำหรับตารางที่กำหนดฉันเห็นแถวพิเศษที่มีชื่อของตารางนั้นในผลลัพธ์ "RowCounts" ของแต่ละแถวพิเศษเหล่านั้นสอดคล้องกับจำนวนแถวที่ครอบคลุมโดยหนึ่งในดัชนีที่กรอง (บน Sql2012)
Akos Lukacs

37
@Todd: บางคนต้องการให้สั่งแบบนั้น - คนอื่นต้องการชื่อตาราง - เลือกของคุณปรับรหัสตามต้องการ ....
marc_s

12
หากตารางของคุณมีการแบ่งพาร์ติชันตารางเหล่านั้นจะปรากฏขึ้นหลายครั้งโดยไม่มีการระบุว่าเกิดอะไรขึ้น คุณสามารถเพิ่ม p.partition_number ในรายการที่เลือกหรือคุณสามารถ SUM (p.Rows) และลบออกจากกลุ่มโดย
PRMan

561

หากคุณใช้SQL Server Management Studio (SSMS) แทนที่จะเรียกใช้แบบสอบถาม ( ซึ่งในกรณีของฉันส่งคืนแถวที่ซ้ำกัน ) คุณสามารถเรียกใช้รายงานมาตรฐานได้ 

  1. คลิกขวาที่ฐานข้อมูล
  2. ไปที่รายงาน> รายงานมาตรฐาน> การใช้ดิสก์ตามตาราง

หมายเหตุ: ระดับความเข้ากันได้ของฐานข้อมูลต้องถูกตั้งค่าเป็น 90 หรือสูงกว่าเพื่อให้สิ่งนี้ทำงานได้อย่างถูกต้อง ดูhttp://msdn.microsoft.com/en-gb/library/bb510680.aspx


54
ใน Management Studio 2012 คุณสามารถทำได้: View-Object Explorer Details (F7) และไปที่ "Tables" ใน Object Explorer ในรายละเอียดคลิกขวาที่ส่วนหัวและเลือกคอลัมน์ขนาด
ValGe

3
สำหรับการแนะนำฟังก์ชั่นใหม่กับ SSMS 2012 สำหรับเราผู้แก่เก่าเราไม่เคยมีสิ่งนี้ ดังนั้นเราก็ไม่ได้มันเป็นวิธีที่ TSQL เก่า :)
GoldBishop

3
เชื่อหรือไม่บางครั้งเป็นเพียงปุถุชน (นักพัฒนา) ต้องการดูข้อมูลนี้และเราไม่ได้รับอนุญาตให้ใช้รายงานในตัว แต่เราสามารถเรียกใช้ TSQL ในคำตอบที่ยอมรับได้ :) FYI (BTW ฉันยัง upvote คำตอบของคุณ)
Andrew Steitz

8
ดูเหมือนจะไม่ปรากฏใน Azure SQL :-(
Simon_Weaver

1
ฉันรู้ว่ามันไม่ได้ร้ายแรง แต่โปรดคุณเพียงแค่ผลักกลุ่มชายขอบออกจากวิศวกรรมและเทคโนโลยีด้วยเหตุผลหลายบรรทัดที่ถูกทำซ้ำทุกที่ คุณควรเรียนรู้ทั้งสองอย่าง แต่ไม่ควรลงโทษผู้คนที่ใช้ยูทิลิตี้ประหยัดเวลาเพื่อทำงานอย่างชาญฉลาดและเร็วขึ้น (แม้ว่า SSMS ดูเหมือนจะเป็น "การลดความเร็วยูทิลิตี้" บางครั้ง ... : X) โดยส่วนตัวแล้วการอ่านค่าข้อมูลแบบแท็บจะมีความชัดเจนมากขึ้นใน GUI แม้ว่าเครื่องมือที่สร้างโดย Microsoft มักจะเป็นข้อยกเว้นสำหรับทุกอย่างที่เกี่ยวข้องกับ UI
Julia McGuigan

102

sp_spaceused สามารถรับข้อมูลเกี่ยวกับพื้นที่ดิสก์ที่ใช้โดยตารางมุมมองที่จัดทำดัชนีหรือฐานข้อมูลทั้งหมด

ตัวอย่างเช่น:

USE MyDatabase; GO

EXEC sp_spaceused N'User.ContactInfo'; GO

สิ่งนี้รายงานข้อมูลการใช้ดิสก์สำหรับตาราง ContactInfo

วิธีใช้สำหรับตารางทั้งหมดในครั้งเดียว:

USE MyDatabase; GO

sp_msforeachtable 'EXEC sp_spaceused [?]' GO

นอกจากนี้คุณยังสามารถใช้งานดิสก์ได้จากภายในคลิกขวาที่ฟังก์ชั่นรายงานมาตรฐานของ SQL Server เมื่อต้องการไปที่รายงานนี้ให้นำทางจากวัตถุเซิร์ฟเวอร์ใน Object Explorer เลื่อนลงไปที่วัตถุฐานข้อมูลแล้วคลิกขวาที่ฐานข้อมูลใด ๆ จากเมนูที่ปรากฏขึ้นให้เลือกรายงานจากนั้นรายงานมาตรฐานจากนั้นเลือก "การใช้ดิสก์ตามพาร์ทิชัน: [ชื่อฐานข้อมูล]"


3
นี่เป็นสิ่งที่เรียบร้อยแม้ว่าการใช้งานsp_msforeachtableใน SSMS อาจก่อให้เกิด a System.OutOfMemoryExceptionหากคุณมีตารางจำนวนมากดังนั้นจึงควรใช้ตารางชั่วคราวเพื่อเก็บผลลัพธ์
syneticon-dj

1
ปัญหาหลักที่ฉันเห็นด้วย sp_spacedused คือดูเหมือนว่าจะส่งคืนข้อมูลในรูปแบบที่มนุษย์อ่านได้ (เช่นในคอลัมน์ 'สงวน' ในกรณีของฉันมี '152 KB') ฉันคิดว่าสิ่งนี้จะเปลี่ยนเป็น MB / GB ตามความเหมาะสม สิ่งนี้มีประโยชน์ชัดเจนในหลาย ๆ สถานการณ์ แต่ไม่ใช่ถ้าคุณจำเป็นต้องใช้ตรรกะบางอย่างตามขนาดหรือต้องการเปรียบเทียบค่าหรืออะไรก็ตาม ฉันมองหาวิธีที่จะปิด แต่ฉันไม่สามารถมองเห็นได้ (ฉันใช้ SQL Server 2005 :()
DarthPablo

55

นี่คือวิธีอื่น: การใช้SQL Server Management StudioในObject Explorerไปที่ฐานข้อมูลของคุณและเลือกตาราง

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

จากนั้นเปิดรายละเอียด Object Explorer (โดยการกดF7หรือไปที่View-> Object Explorer Details ) ในหน้ารายละเอียดนักสำรวจวัตถุคลิกขวาที่ส่วนหัวคอลัมน์และเปิดใช้งานคอลัมน์ที่คุณต้องการดูในหน้า คุณสามารถเรียงลำดับข้อมูลตามคอลัมน์ใดก็ได้เช่นกัน

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


ใช่ SSMS ใน Azure ขาดคุณสมบัติบางอย่างเมื่อเทียบกับรุ่นท้องถิ่น
นกกระจอก

@batmaci ไม่แน่ใจว่าสิ่งนี้ทำงานได้ดีหรือไม่เมื่อคุณแสดงความคิดเห็นเกี่ยวกับฐานข้อมูล Azure SQL แต่อย่างน้อยก็ดูเหมือนว่าจะทำงานได้บางส่วนใน SSMS รุ่นล่าสุด สำหรับฉันดูเหมือนว่าการสืบค้นข้อมูลเมตาของตารางจะหมดเวลา แต่ก่อนหน้านี้ดูเหมือนว่าจะส่งคืนมูลค่าตาราง 2-3 ตาราง (2-3 รายการ) รวมถึง (ตารางที่เลือก) ที่เชื่อถือได้ เลือกตารางและคลิกรีเฟรชเพื่อดูตารางที่คุณต้องการหากไม่ปรากฏ
pcdev

สีฟ้าไม่ใช่ SQL Server ที่ "จริง" (ฮ่า)
วิศวกรที่กลับรายการแล้ว

ฉันใช้มันกับ Azure ขอบคุณด้วย (บวกหนึ่ง)
Irf

นอกจากนี้คุณยังสามารถส่งออกรายการในไฟล์ CSV โดยใช้โปรแกรมอรรถประโยชน์เช่น NirSoft SysExporter: nirsoft.net/utils/sysexp.html
สูงสุด

39

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

สคริปต์ต่อไปนี้จะสร้างข้อมูลที่ฉันกำลังมองหา

create table #TableSize (
    Name varchar(255),
    [rows] int,
    reserved varchar(255),
    data varchar(255),
    index_size varchar(255),
    unused varchar(255))
create table #ConvertedSizes (
    Name varchar(255),
    [rows] int,
    reservedKb int,
    dataKb int,
    reservedIndexSize int,
    reservedUnused int)

EXEC sp_MSforeachtable @command1="insert into #TableSize
EXEC sp_spaceused '?'"
insert into #ConvertedSizes (Name, [rows], reservedKb, dataKb, reservedIndexSize, reservedUnused)
select name, [rows], 
SUBSTRING(reserved, 0, LEN(reserved)-2), 
SUBSTRING(data, 0, LEN(data)-2), 
SUBSTRING(index_size, 0, LEN(index_size)-2), 
SUBSTRING(unused, 0, LEN(unused)-2)
from #TableSize

select * from #ConvertedSizes
order by reservedKb desc

drop table #TableSize
drop table #ConvertedSizes

หลังจากได้เห็นข้างต้นโดยใช้ foreach และ SP กำลังจะเขียนอะไรเช่นนี้ดีใจที่ฉันเลื่อนลงเพื่อดูว่ามันช่วยฉันสักหน่อย
แบรด

37
 exec  sp_spaceused N'dbo.MyTable'

สำหรับตารางทั้งหมดใช้ .. (เพิ่มจากความคิดเห็นของ Paul)

exec sp_MSForEachTable 'exec sp_spaceused [?]'

5
ส่อเสียด - คุณเปลี่ยนจากการexec sp_helpdbที่ไม่แสดงอะไรเกี่ยวกับตารางexec sp_spaceusedที่จะ - แต่เพียงครั้งละหนึ่งตาราง ... มันไม่ได้ให้ภาพรวมของสิ่งที่คุณมีตารางและจำนวนแถวที่พวกเขามีและวิธี พวกเขาใช้พื้นที่มาก
marc_s

4
exec sp_MSForEachTable 'exec sp_spaceused [?]'
พอล

27

ข้อความค้นหาด้านบนนั้นดีสำหรับการค้นหาจำนวนพื้นที่ที่ใช้โดยตาราง (รวมดัชนี) แต่ถ้าคุณต้องการเปรียบเทียบว่าดัชนีพื้นที่บนตารางมีการใช้พื้นที่เท่าใดให้ใช้แบบสอบถามนี้:

SELECT
    OBJECT_NAME(i.OBJECT_ID) AS TableName,
    i.name AS IndexName,
    i.index_id AS IndexID,
    8 * SUM(a.used_pages) AS 'Indexsize(KB)'
FROM
    sys.indexes AS i
    JOIN sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id
    JOIN sys.allocation_units AS a ON a.container_id = p.partition_id
WHERE
    i.is_primary_key = 0 -- fix for size discrepancy
GROUP BY
    i.OBJECT_ID,
    i.index_id,
    i.name
ORDER BY
    OBJECT_NAME(i.OBJECT_ID),
    i.index_id

เหตุผลที่รวมคอลัมน์ Indexsize (KB) สำหรับตารางที่เฉพาะเจาะจงไม่เห็นด้วยกับ index_size จาก sp_spaceused คืออะไร
ดีเร็ก

@Derek where [i].[is_primary_key] = 0คงคำตอบของเขาโดยการเพิ่ม ตอนนี้ขนาดควรตรงกับ
CodeAngry

ขอบคุณ แต่สิ่งนี้ไม่ได้ผลเช่นกัน ฉันมีฐานข้อมูลการทดสอบ (เล็กมาก) ตารางที่น่าสนใจมีสองดัชนี - ดัชนีคลัสเตอร์หลักในหนึ่งคอลัมน์และดัชนีที่ไม่ใช่คลัสเตอร์ในสองคอลัมน์อื่น ๆ แบบสอบถามนี้ระบุว่าแต่ละรายการใช้ 16kB แต่ sp_spaceused กล่าวว่าการใช้ดัชนีทั้งหมดคือ 24kB ส่วนหนึ่งของความสับสนของฉันคือ: การเปรียบเทียบแบบสอบถามนี้กับ "UsedSpaceKB" ของคำตอบที่ยอมรับฉันไม่เห็นความแตกต่างที่แท้จริง การเข้าร่วมเดียวกันเพิ่งเพิ่ม sys.tables ฉันขาดอะไรไปหรือคิวรี่นี้ขาดหรือไม่
ดีเร็ก

ฉันมีฐานข้อมูลขนาดใหญ่ sp_spaceusedและขนาดที่เหมาะสมกับ ฉันวัด GBs ดังนั้นไม่กี่ megs ที่ไม่ตรงกันไม่มาก ฉันไม่สนใจขนาดที่แน่นอนเพียงแค่ความคิด
CodeAngry

14

หากคุณต้องการคำนวณตัวเลขเดียวกันทั้งหมดที่อยู่ในหน้า 'คุณสมบัติตาราง - พื้นที่เก็บข้อมูล' ใน SSMS คุณต้องนับด้วยวิธีเดียวกับที่ทำใน SSMS (ทำงานกับเซิร์ฟเวอร์ sql 2005 และสูงกว่า ... และยัง ทำงานอย่างถูกต้องสำหรับตารางที่มีเขตข้อมูล LOB เนื่องจากการนับ "used_pages" ไม่เพียงพอที่จะแสดงขนาดดัชนีที่ถูกต้อง):

;with cte as (
SELECT
t.name as TableName,
SUM (s.used_page_count) as used_pages_count,
SUM (CASE
            WHEN (i.index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)
            ELSE lob_used_page_count + row_overflow_used_page_count
        END) as pages
FROM sys.dm_db_partition_stats  AS s 
JOIN sys.tables AS t ON s.object_id = t.object_id
JOIN sys.indexes AS i ON i.[object_id] = t.[object_id] AND s.index_id = i.index_id
GROUP BY t.name
)
select
    cte.TableName, 
    cast((cte.pages * 8.)/1024 as decimal(10,3)) as TableSizeInMB, 
    cast(((CASE WHEN cte.used_pages_count > cte.pages 
                THEN cte.used_pages_count - cte.pages
                ELSE 0 
          END) * 8./1024) as decimal(10,3)) as IndexSizeInMB
from cte
order by 2 desc

14

ขยายไปยังคำตอบ @xav ที่จัดการพาร์ติชันตารางเพื่อรับขนาดเป็น MB และ GB ทดสอบบน SQL Server 2008/2012 (แสดงความคิดเห็นในบรรทัดที่is_memory_optimized = 1)

SELECT
    a2.name AS TableName,
    a1.rows as [RowCount],
    --(a1.reserved + ISNULL(a4.reserved,0)) * 8 AS ReservedSize_KB,
    --a1.data * 8 AS DataSize_KB,
    --(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS IndexSize_KB,
    --(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS UnusedSize_KB,
    CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_MB,
    CAST(ROUND(a1.data * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_MB,
    CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_MB,
    CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_MB,
    --'| |' Separator_MB_GB,
    CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_GB,
    CAST(ROUND(a1.data * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_GB,
    CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_GB,
    CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_GB
FROM
    (SELECT 
        ps.object_id,
        SUM (CASE WHEN (ps.index_id < 2) THEN row_count ELSE 0 END) AS [rows],
        SUM (ps.reserved_page_count) AS reserved,
        SUM (CASE
                WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
            END
            ) AS data,
        SUM (ps.used_page_count) AS used
    FROM sys.dm_db_partition_stats ps
        --===Remove the following comment for SQL Server 2014+
        --WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
    GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN 
    (SELECT 
        it.parent_id,
        SUM(ps.reserved_page_count) AS reserved,
        SUM(ps.used_page_count) AS used
     FROM sys.dm_db_partition_stats ps
     INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
     WHERE it.internal_type IN (202,204)
     GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id ) 
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
--AND a2.name = 'MyTable'       --Filter for specific table
--ORDER BY a3.name, a2.name
ORDER BY ReservedSize_MB DESC

ยังเรียงลำดับที่ดีกว่า
Pxtl

นี่ควรเป็นคำตอบที่ดีที่สุด
Baodad

14

สำหรับ Azure ฉันใช้สิ่งนี้:

คุณควรมี SSMS v17.x

ฉันใช้;

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

ด้วยสิ่งนี้ตามที่ผู้ใช้ พูดถึง :

เปิดของคุณDatabases> และเลือกตาราง ,
จากนั้นกดปุ่มF7 คุณควรจะดูrow count
เป็น: ป้อนคำอธิบายรูปภาพที่นี่

SSMS ที่นี่เชื่อมต่อกับฐานข้อมูล Azure


3
F7 มีการใช้งานน้อยมาก
cskwg

1
ฉันไม่รู้ว่าสิ่งนี้มีอยู่ฉันละอายใจตัวเอง: p ขอบคุณ!
lollancf37

มันมีปัญหากับตารางที่ปรับให้เหมาะสมกับหน่วยความจำ (ฉันเพิ่งทดสอบหลังจากดูโพสต์นี้ :)
Amirreza

11

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

สำหรับผู้ที่ต้องการสิ่งนี้คุณสามารถค้นหาแบบสอบถามด้านล่างซึ่งดำเนินการโดย SQL Server 2014 เมื่อสร้างรายงาน "การใช้ดิสก์ตามตาราง" ฉันถือว่ามันใช้งานได้กับ SQL Server รุ่นก่อนหน้าด้วย

มันทำงานเหมือนจับใจ

SELECT
    a2.name AS [tablename],
    a1.rows as row_count,
    (a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved, 
    a1.data * 8 AS data,
    (CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,
    (CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused
FROM
    (SELECT 
        ps.object_id,
        SUM (
            CASE
                WHEN (ps.index_id < 2) THEN row_count
                ELSE 0
            END
            ) AS [rows],
        SUM (ps.reserved_page_count) AS reserved,
        SUM (
            CASE
                WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
                ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
            END
            ) AS data,
        SUM (ps.used_page_count) AS used
    FROM sys.dm_db_partition_stats ps
        WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
    GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN 
    (SELECT 
        it.parent_id,
        SUM(ps.reserved_page_count) AS reserved,
        SUM(ps.used_page_count) AS used
     FROM sys.dm_db_partition_stats ps
     INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
     WHERE it.internal_type IN (202,204)
     GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id ) 
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
ORDER BY a3.name, a2.name

ขอบคุณสำหรับสคริปต์ที่ตรงกับวิธีที่ SSMS ทำและจัดการพาร์ติชันอย่างเหมาะสม
Mike

8
-- Show the size of all the tables in a database sort by data size descending
SET NOCOUNT ON
DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
DECLARE @cmd1 varchar(500)
SET @cmd1 = 'exec sp_spaceused ''?'''

INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
EXEC sp_msforeachtable @command1=@cmd1

SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC

8

การเปลี่ยนแปลงเล็กน้อยในคำตอบของ Mar_cเนื่องจากฉันได้กลับมาที่หน้านี้บ่อยๆสั่งโดยแถวแรกสุด:

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 NOT LIKE 'dt%'
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
GROUP BY
    t.Name, s.Name, p.Rows
ORDER BY
    --p.rows DESC --Uncomment to order by amount rows instead of size in KB.
    SUM(a.total_pages) DESC 

5

สิ่งนี้จะทำให้คุณมีขนาดและบันทึกการนับสำหรับแต่ละตาราง

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
-- Get a list of tables and their sizes on disk
ALTER PROCEDURE [dbo].[sp_Table_Sizes]
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
DECLARE @table_name VARCHAR(500)  
DECLARE @schema_name VARCHAR(500)  
DECLARE @tab1 TABLE( 
        tablename VARCHAR (500) collate database_default 
       ,schemaname VARCHAR(500) collate database_default 
) 

CREATE TABLE #temp_Table ( 
        tablename sysname 
       ,row_count INT 
       ,reserved VARCHAR(50) collate database_default 
       ,data VARCHAR(50) collate database_default 
       ,index_size VARCHAR(50) collate database_default 
       ,unused VARCHAR(50) collate database_default  
) 

INSERT INTO @tab1  
SELECT Table_Name, Table_Schema  
FROM information_schema.tables  
WHERE TABLE_TYPE = 'BASE TABLE' 

DECLARE c1 CURSOR FOR 
SELECT Table_Schema + '.' + Table_Name   
FROM information_schema.tables t1  
WHERE TABLE_TYPE = 'BASE TABLE' 

OPEN c1 
FETCH NEXT FROM c1 INTO @table_name 
WHILE @@FETCH_STATUS = 0  
BEGIN   
        SET @table_name = REPLACE(@table_name, '[','');  
        SET @table_name = REPLACE(@table_name, ']','');  

        -- make sure the object exists before calling sp_spacedused 
        IF EXISTS(SELECT id FROM sysobjects WHERE id = OBJECT_ID(@table_name)) 
        BEGIN 
               INSERT INTO #temp_Table EXEC sp_spaceused @table_name, false; 
        END 

        FETCH NEXT FROM c1 INTO @table_name 
END 
CLOSE c1 
DEALLOCATE c1 

SELECT  t1.* 
       ,t2.schemaname  
FROM #temp_Table t1  
INNER JOIN @tab1 t2 ON (t1.tablename = t2.tablename ) 
ORDER BY schemaname,t1.tablename; 

DROP TABLE #temp_Table
END

2
หากคุณโพสต์โค้ด, XML หรือตัวอย่างข้อมูลโปรดเน้นบรรทัดเหล่านั้นในโปรแกรมแก้ไขข้อความและคลิกที่ปุ่ม "ตัวอย่างรหัส" ( { }) บนแถบเครื่องมือตัวแก้ไขเพื่อจัดรูปแบบและเน้นไวยากรณ์!
marc_s

4

รับขนาดตารางทั้งหมดในฐานข้อมูลเดียวคุณสามารถใช้แบบสอบถามนี้:

Exec sys.sp_MSforeachtable ' sp_spaceused "?" '

และคุณสามารถเปลี่ยนเพื่อแทรกผลลัพธ์ทั้งหมดลงในตารางอุณหภูมิและหลังจากนั้นเลือกจากตารางอุณหภูมิ

Insert into #TempTable Exec sys.sp_MSforeachtable ' sp_spaceused "?" ' 
Select * from #TempTable


3

นี่คือวิธีในการรับขนาดตารางทั้งหมดอย่างรวดเร็วด้วยขั้นตอนต่อไปนี้:

  1. เขียนคำสั่ง T-SQL ที่กำหนดเพื่อแสดงรายการตารางฐานข้อมูลทั้งหมด:

    select 'exec sp_spaceused ' + TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'
  2. ตอนนี้คัดลอกรายการของตารางฐานข้อมูลและคัดลอกลงในหน้าต่างตัววิเคราะห์แบบสอบถามใหม่

    exec sp_spaceused table1
    exec sp_spaceused table2
    exec sp_spaceused table3
    exec sp_spaceused table4
    exec sp_spaceused table5
  3. ในตัววิเคราะห์คิวรี SQL เลือกจากแถบเครื่องมือตัวเลือกตัวเลือกResults to file ( Ctrl+ Shift+ F)

  4. ตอนนี้จนตีExecuteปุ่มสีแดงที่ทำเครื่องหมายไว้จากด้านบนแถบเครื่องมือ

  5. ขณะนี้ขนาดฐานข้อมูลของตารางทั้งหมดถูกจัดเก็บในไฟล์บนคอมพิวเตอร์ของคุณ

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


2

ฉันเพิ่มคอลัมน์อีกสองสามรายการที่ด้านบนของคำตอบ marc_s:

with fs
as
(
select i.object_id,
        p.rows AS RowCounts,
        SUM(a.total_pages) * 8 AS TotalSpaceKb
from     sys.indexes i 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
WHERE 
    i.OBJECT_ID > 255 
GROUP BY 
    i.object_id,
    p.rows
)

SELECT 
    t.NAME AS TableName,
    fs.RowCounts,
    fs.TotalSpaceKb,
    t.create_date,
    t.modify_date,
    ( select COUNT(1)
        from sys.columns c 
        where c.object_id = t.object_id ) TotalColumns    
FROM 
    sys.tables t INNER JOIN      
    fs  ON t.OBJECT_ID = fs.object_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
ORDER BY 
    t.Name

1

โพสต์ของฉันเกี่ยวข้องเฉพาะกับ SQL Server 2000 และได้รับการทดสอบให้ทำงานในสภาพแวดล้อมของฉัน

รหัสนี้เข้าถึงฐานข้อมูลที่เป็นไปได้ทั้งหมดของอินสแตนซ์เดียวไม่ใช่ฐานข้อมูลเดียว

ฉันใช้ตารางชั่วคราวสองตารางเพื่อช่วยรวบรวมข้อมูลที่เหมาะสมจากนั้นถ่ายโอนข้อมูลผลลัพธ์ลงในตาราง 'สด'

ข้อมูลที่ส่งคืนคือ: DatabaseName, DatabaseTableName, แถว (ในตาราง), ข้อมูล (ขนาดของตารางในหน่วย KB ที่ดูเหมือนจะเป็น), ข้อมูลรายการ (ฉันพบว่ามีประโยชน์สำหรับการรู้เมื่อฉันเรียกใช้สคริปต์ครั้งล่าสุด)

ความตกต่ำของรหัสนี้คือฟิลด์ 'data' ไม่ได้ถูกจัดเก็บในรูปแบบ int (ตัวอักษร 'KB' จะถูกเก็บไว้ในฟิลด์นั้น) และนั่นจะเป็นประโยชน์ (แต่ไม่จำเป็นทั้งหมด) สำหรับการเรียงลำดับ

หวังว่ารหัสนี้จะช่วยให้ใครบางคนที่นั่นและช่วยพวกเขาในบางเวลา!

CREATE PROCEDURE [dbo].[usp_getAllDBTableSizes]

AS
BEGIN
   SET NOCOUNT OFF

   CREATE TABLE #DatabaseTables([dbname] sysname,TableName sysname)
   CREATE TABLE #AllDatabaseTableSizes(Name sysname,[rows] VARCHAR(18), reserved VARCHAR(18), data VARCHAR(18), index_size VARCHAR(18), unused VARCHAR(18))

   DECLARE @SQL nvarchar(4000)
   SET @SQL='select ''?'' AS [Database], Table_Name from [?].information_schema.tables WHERE TABLE_TYPE = ''BASE TABLE'' '

   INSERT INTO #DatabaseTables(DbName, TableName)
      EXECUTE sp_msforeachdb @Command1=@SQL

   DECLARE AllDatabaseTables CURSOR LOCAL READ_ONLY FOR   
   SELECT TableName FROM #DatabaseTables

   DECLARE AllDatabaseNames CURSOR LOCAL READ_ONLY FOR   
   SELECT DBName FROM #DatabaseTables

   DECLARE @DBName sysname  
   OPEN AllDatabaseNames  

   DECLARE @TName sysname
   OPEN AllDatabaseTables  

   WHILE 1=1 BEGIN 
      FETCH NEXT FROM AllDatabaseNames INTO @DBName  
      FETCH NEXT FROM AllDatabaseTables INTO @TName 
      IF @@FETCH_STATUS<>0 BREAK  
      INSERT INTO #AllDatabaseTableSizes
         EXEC ( 'EXEC ' + @DBName + '.dbo.sp_spaceused ' + @TName) 

   END 

   --http://msdn.microsoft.com/en-us/library/aa175920(v=sql.80).aspx
   INSERT INTO rsp_DatabaseTableSizes (DatabaseName, name, [rows], data)
      SELECT   [dbname], name, [rows],  data FROM #DatabaseTables
      INNER JOIN #AllDatabaseTableSizes
      ON #DatabaseTables.TableName = #AllDatabaseTableSizes.Name
      GROUP BY [dbname] , name, [rows],  data
      ORDER BY [dbname]
   --To be honest, I have no idea what exact duplicates we are dropping
    -- but in my case a near enough approach has been good enough.
   DELETE FROM [rsp_DatabaseTableSizes]
   WHERE name IN 
      ( 
      SELECT name 
      FROM [rsp_DatabaseTableSizes]
      GROUP BY name
      HAVING COUNT(*) > 1
      )

   DROP TABLE #DatabaseTables
   DROP TABLE #AllDatabaseTableSizes

   CLOSE AllDatabaseTables  
   DEALLOCATE AllDatabaseTables  

   CLOSE AllDatabaseNames  
   DEALLOCATE AllDatabaseNames      
END

--EXEC [dbo].[usp_getAllDBTableSizes] 

ในกรณีที่คุณจำเป็นต้องรู้ตารางrsp_DatabaseTableSizesถูกสร้างขึ้นผ่าน:

CREATE TABLE [dbo].[rsp_DatabaseSizes](
    [DatabaseName] [varchar](1000) NULL,
    [dbSize] [decimal](15, 2) NULL,
    [DateUpdated] [smalldatetime] NULL
) ON [PRIMARY]

GO

1

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

SELECT *
FROM
(

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    COUNT(DISTINCT c.COLUMN_NAME) as ColumnCount,
    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
INNER JOIN
    INFORMATION_SCHEMA.COLUMNS c ON t.NAME = c.TABLE_NAME
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
GROUP BY 
    t.Name, s.Name, p.Rows
) AS Result

WHERE
    RowCounts > 1000
    AND ColumnCount > 10
ORDER BY 
    UsedSpaceKB DESC

หลังจากคุณเข้าร่วมตารางคอลัมน์แล้วคุณจะไม่มีพื้นที่ตารางที่เหมาะสมอีกต่อไป การใช้ภายนอกจะเป็นการแก้ไข
dreamca4er

0

การตอบคำถามบน @Mark ข้างต้นเพิ่ม @ updateusage = 'true' เพื่อบังคับสถิติขนาดล่าสุด ( https://msdn.microsoft.com/en-us/library/ms188776.aspx ):

        SET NOCOUNT ON
        DECLARE @TableInfo TABLE (tablename varchar(255), rowcounts int, reserved varchar(255), DATA varchar(255), index_size varchar(255), unused varchar(255))
        DECLARE @cmd1 varchar(500)
        SET @cmd1 = 'exec sp_spaceused @objname =''?'', @updateusage =''true'' '

        INSERT INTO @TableInfo (tablename,rowcounts,reserved,DATA,index_size,unused)
        EXEC sp_msforeachtable @command1=@cmd1 
SELECT * FROM @TableInfo ORDER BY Convert(int,Replace(DATA,' KB','')) DESC

0

นี่คือแบบสอบถามตัวอย่างเพื่อรับตารางที่มีขนาดใหญ่กว่า 1GB เรียงจากขนาดจากมากไปน้อย

USE YourDB
GO

DECLARE @Mult float = 8
SET @Mult = @Mult / POWER(2, 20) -- Use POWER(2, 10) for MBs

; WITH CTE AS
(
SELECT
    i.object_id,
    Rows = MAX(p.rows),
    TotalSpaceGB = ROUND(SUM(a.total_pages) * @Mult, 0),
    UsedSpaceGB = ROUND(SUM(a.used_pages) * @Mult, 0)
FROM 
    sys.indexes i
JOIN
    sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE
    i.object_id > 255
GROUP BY
    i.object_id
HAVING
    SUM(a.total_pages) * @Mult > 1
)
SELECT 
    SchemaName = s.name,
    TableName = t.name,
    c.TotalSpaceGB,
    c.UsedSpaceGB,
    UnusedSpaceGB = c.TotalSpaceGB - c.UsedSpaceGB,
    [RowCount] = c.Rows
FROM 
    CTE c
JOIN    
    sys.tables t ON t.object_id = c.object_id
JOIN
    sys.schemas s ON t.schema_id = s.schema_id
ORDER BY
    c.TotalSpaceGB DESC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.