Friday, 15 May 2026

SQLDBA- SQL Server Management Studio 22 Download, Install and Configure

 

SQL Server Management Studio 22 Download, Install and Configure

 

This article describes how to install SQL Server Management Studio (SSMS). Below are the key notes.

 

Key information

Action required

SSMS 22 is installed with the Visual Studio Installer

The SSMS 22 installer link downloads a stub installer (vs_SSMS.exe) that opens Visual Studio Installer to install SSMS. There's no standalone MSI.

How to install SSMS

Download the SSMS 22 installer, run vs_SSMS.exe, pick any optional workloads/components, then select Install.

Use the Visual Studio Installer to update SSMS 22

To update SSMS 22, follow the instructions in Update SQL Server Management Studio.

Offline or enterprise deployment

To create an offline layout for disconnected or managed installs, see Create an offline installation of SQL Server Management Studio.

Database Engine compatibility

SSMS 22 works with SQL Server 2014 (12.x) and later versions. If you need to manage older versions, see the Release history. SSMS 22 also works with Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, and SQL database in Microsoft Fabric.

 

Step1. If we want to install SSMS 22, before that we need to download a stub installer (vs_SSMS.exe). below link use to download the vs_SSMS.exe

Release Notes for SQL Server Management Studio (SSMS) | Microsoft Learn

A screenshot of a computer

AI-generated content may be incorrect.

Step2:  After completion of step1, go the download files location and right click on vs_SSMS.exe file  and select   Run as administrator

A screenshot of a computer

AI-generated content may be incorrect.

A screenshot of a computer

AI-generated content may be incorrect.

 

 

A screenshot of a computer

AI-generated content may be incorrect.

 

 

 

 

Step3: Click on Continue

A screenshot of a computer software installer

AI-generated content may be incorrect.

The installer will install it as part of Visual Studio.

A screenshot of a software

AI-generated content may be incorrect.

 

Step4: if we have previous versions of SSMS, you can copy the workloads, components, and settings to the new version. Also, you can select your vsconf file. This file is in JSON format and shows the components to install.

Below window will appear if we have  SSMS21 version.

A screenshot of a computer

AI-generated content may be incorrect.

 

If you have a previous version installed, you may receive a message that some packages are not available. Click on Ok

A screenshot of a computer

AI-generated content may be incorrect.

 

 

Step5: After this, press the Install button as shown below.

 

A screenshot of a computer

AI-generated content may be incorrect.

 

Step6: Finally, the installer may ask you to restart the machine.

A screenshot of a computer

AI-generated content may be incorrect.

 

 

 

Upgrade SQL Server Management Studio 22

1. Launch Visual Studio Installer

  1. Press Start.
  2. Type Visual Studio Installer.
  3. Click to open it.

 

2. Locate SSMS in Installed Components

  1. In Visual Studio Installer, go to the Installed tab.
  2. Scroll to find SQL Server Management Studio listed as an installed component.

A screenshot of a computer

AI-generated content may be incorrect.

3. Check for SSMS Updates

  • If an update is available, you will see an Update button next to SSMS.
  • If the button is not visible, your SSMS is already up to date.

A screenshot of a computer

AI-generated content may be incorrect.


4. Apply the Update

  1. Click Update.
  2. The Visual Studio Installer downloads only the necessary component updates.
  3. Wait until the progress bar completes.

A screenshot of a computer

AI-generated content may be incorrect.


5. Complete the Installation

  • When the update finishes, the Installer will show Completed.
  • No reboot is usually required unless prompted.

 


6. Verify the Upgrade

  1. Open SQL Server Management Studio.
  2. Click Help → About.
  3. Confirm the SSMS version is now updated.

 


7. Notes and Best Practices

  • Ignore SSMS upgrade popup notifications inside SSMS itself — updates must go through Visual Studio Installer.
  • The SSMS .exe from Microsoft’s website is only a bootstrapper and will automatically redirect to Visual Studio Installer.

 

SQLDBA- What breaks with SQL server 2025

 

SQL Server 2025 known issues:

 With SQL Server 2025, Microsoft has introduced a major change in the OLE DB provider

·       MSOLEDBSQL 19 is now the default provider

The new provider enforces:

  • Encrypt = TRUE (default)
  • TrustServerCertificate = FALSE (default)
  • Strict certificate chain validation

 

Impact: Connections will fail by default

 If our environment uses:

  • Self-signed certificates
  • Internal CA not trusted
  • Or no encryption

 

Affected Components

This change impacts:

  • Linked Servers
  • Replication
  • Log Shipping
  • Applications using legacy connection strings

Earlier:

  • SQLNCLI (old provider) ignored certificate validation issues

Now:

  • MSOLEDBSQL 19 enforces strict security

 

1. Linked Servers Fail After Upgrade

Issue

  • Linked servers fail due to mandatory encryption changes in SQL Server  2025
  • If We configured linked servers using SQLNCLI (which was the default for years), they'll fail after upgrade with errors like:
  • Errors: 7303, SSL trust, certificate issues [mssqltips.com], [learn.microsoft.com]

Msg 7303, Level 16, State 1

Cannot initialize the data source object of OLE DB provider "MSOLEDBSQL" for linked server "<linked server name>".

TCP Provider: The certificate chain was issued by an authority which is not trusted.

Msg 10054, Level 20, State 0 

A transport-level error occurred when receiving results from the server.

Msg 17832, Level 20, State 18

The login packet used to open the connection is structurally invalid; the connection has been closed.

[SQL Server]The target principal name is incorrect

Root Cause

SQL Server 2025 enforces :

  • Encrypt = TRUE by default
  • Strict TLS certificate validation

The fix is to either install proper certificates or reconfigure the linked server with TrustServerCertificate=yes — which defeats the security improvement but at least gets you running.

Fix Option 1 (Quick workaround) This bypasses certificate validation.  Not recommended for long-term use

EXEC sp_addlinkedserver

@server='MyServer',

@provider='MSOLEDBSQL',

@datasrc='ServerName',

@provstr='Encrypt=Yes;TrustServerCertificate=True';

 

Fix Option 2 (Best Practice – Recommended)

  1. Install valid SSL certificate on SQL Server

 

 

 


2. Replication Failure After Upgrade

Issue

Replication breaks due to encryption + certificate mismatch [learn.microsoft.com]

If publisher is SQL Server 2025 and your distributor is remote without a trusted certificate, replication will fail. You'll see:

 

OLE DB provider "MSOLEDBSQL19" for linked server "repl_distributor" returned message 
"Client unable to establish connection".
 
Msg -2146893019, Level 16, State 1
SSL Provider: The certificate chain was issued by an authority that is not trusted.

 

This hits transactional, snapshot, peer-to-peer, and merge replication. Replication Monitor in SSMS will also fail if it can't validate the certificate chain.

The workaround (if you can't deploy trusted certificates yet):

EXEC sp_changedistributor_property 
    @property = N'trust_distributor_certificate', 
    @value = N'yes';

 

Symptoms

  • Replication monitor fails
  • Publication changes fail

Fix

  1. Configure trusted certificate on all nodes
  2. Verify linked server between publisher & distributor
  3. Restart SQL Agent
  4. Reinitialize replication if required

 

 

3.  Full-Text Search

Issue

SQL Server 2025 introduces a new full-text index version. Existing catalogs stay on version 1 (unchanged since 2005) unless you manually upgrade them. After the engine upgrades, your full-text queries will fail:

Msg 30010, Level 16, State 2
An error has occurred during the full-text query. Common causes include: 
word-breaking errors or timeout, FDHOST permissions/ACL issues, 
service account missing privileges, malfunctioning IFilters...

 

Fix:

The fix is to rebuild your full-text indexes — or if you need to keep using the old version temporarily:

ALTER DATABASE SCOPED CONFIGURATION SET FULLTEXT_INDEX_VERSION = 1;

But version 1 is deprecated. This is a temporary workaround, not a long-term solution.

Full text search won’t index all of big plaintext documents whose size is larger than 25MB. The workaround is to edit the registry to remove the 25MB limit.


4.  Database Mail  another bug 

Issue: After upgrading to SQL Server 2025, Database Mail may stop working mainly due to enforced TLS/SSL requirements, disabled configuration, or SMTP compatibility issues.

 

What happens to Database Mail after upgrade to SQL Server 2025

  • Emails not sending
  • SQL Agent alerts not working
  • Error like:
  • The SMTP server requires a secure connection
  • Messages stuck in queue

 

 Step-by-step approach

Check if DB Mail is enabled- If the below query result output value 0 then enable it.

SELECT value_in_use FROM sys.configurations WHERE name = 'Database Mail XPs';

 

If 0 → enable it:

EXEC sp_configure 'show advanced options', 1;

RECONFIGURE;

 

EXEC sp_configure 'Database Mail XPs', 1;

RECONFIGURE;

 

Check service status

EXEC msdb.dbo.sysmail_help_status_sp;

If stopped:

EXEC msdb.dbo.sysmail_start_sp;

 

Fix SMTP security

EXEC msdb.dbo.sysmail_update_account_sp

    @account_name = 'YourAccount',

    @enable_ssl = 1,

    @port = 587;

 Use TLS-enabled SMTP (587 or 465)

 Not old port 25 (unless secured)

 

Check failures & queue

SELECT *  FROM msdb.dbo.sysmail_allitems ORDER BY send_request_date DESC;

SELECT * FROM msdb.dbo.sysmail_event_log ORDER BY log_date DESC;

 

 

Restart queue (if stuck)

EXEC msdb.dbo.sysmail_stop_sp;

EXEC msdb.dbo.sysmail_start_sp;

Validate network & permissions

Ensure:

  • SQL Server service account has access to SMTP
  • Firewall allows:
    • Port 587 (recommended)

TEST email

EXEC msdb.dbo.sp_send_dbmail

    @profile_name = 'YourProfile',

    @recipients = 'your@email.com',

    @subject = 'Test Mail',

    @body = 'Test after upgrade';

 

 

5. SSIS / Visual Studio Issues

Issue

Old SSIS packages fail to open or upgrade

Fix

  1. Install SSDT (SSIS extension) in VS 2026
  2. Open project → upgrade packages
  3. Replace deprecated providers (SQLNCLI → MSOLEDBSQL)
  4. Reconfigure connection managers

 

 

6. Installation Errors (General)

Common Issues

  • .NET missing
  • WMI service failure
  • OS patch missing

Fix Steps

  1. Install:
    • .NET 4.7.2+
  2. Run:
  3. sfc /scannow
  4. Ensure WMI service is running
  5. Apply Windows updates
  6. Run installer as Administrator

7. Installation Failure (TLS 1.2 Disabled)

Issue

 SQL Server 2025 (17.x) installation fails if TLS 1.2 is disabled on the machine, including failover cluster instances.

Workaround: Enable TLS 1.2 on the machine before attempting to install SQL Server 2025 (17.x).  [learn.microsoft.com]

Fix (Step-by-step)

  1. Open Registry Editor
  2. Navigate to:
  3. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
  4. Enabled TLS 1.2 (Client & Server = Enabled = 1)
  5. Restart the server
  6. Re-run SQL Server installation

After successfully installation of SQL Server 2025, we need to disable the TLS 1.2

7.       Turn it back off again.

 

 

Tuesday, 5 May 2026

SQLDBA- Get the jobs list running with 32 Bit

 

Hi, 

We have an issue with CPU spikes   and we observed that the SQL server integration services execute package utility 32 is  consuming high CPU. So, we  have to find out  which job is running with 32 bit. 



Below query  will help us figure out what  jobs causing the  issue. 

USE msdb;

GO

SELECT * FROM (

SELECT

    j.name        AS job_name,

    js.step_id,

    js.step_name,

    js.subsystem,

    js.command,

    CASE 

        WHEN js.command LIKE '%/X86%' THEN 'Yes'

        ELSE 'No'

    END AS runs_32_bit,

    js.last_run_outcome

,js.flags 

FROM dbo.sysjobsteps js

JOIN dbo.sysjobs j

    ON js.job_id = j.job_id

WHERE js.subsystem = 'SSIS'

)a WHERE runs_32_bit='yes'

--ORDER BY j.name, js.step_id;

Tuesday, 28 April 2026

SQLDBA-Login script out

 Hi Team, 

I got requirement to compare the login with  role of two instance. i have used below query   run in one instance  and load the data into staging data base . and export that table to another  instance and run that  query  another  instance compare both result sets. 


CREATE TABLE #LoginPermissions 

(

ID INteger  IDENTITY(1,1),

DBname VARCHAR(100),

LoginName  VARCHAR(1000),

DatabaseUser VARCHAR(1000),

RoleName  VARCHAR(1000)

)

EXEC sp_MSforeachdb '

USE [?];


INSERT INTO #LoginPermissions (DBname,LoginName,DatabaseUser,RoleName)

SELECT

''?'' as Data_Base_name,

    sp.name  AS LoginName,

    dp.name  AS DatabaseUser,

    dr.name  AS RoleName

FROM sys.server_principals sp

JOIN sys.database_principals dp

    ON sp.sid = dp.sid

JOIN sys.database_role_members drm

    ON dp.principal_id = drm.member_principal_id

JOIN sys.database_principals dr

    ON drm.role_principal_id = dr.principal_id

ORDER BY sp.name, dr.name;

'


SELECT sLP.LoginName,sLP.DatabaseUser,sLP.DBname , sLP.RoleName

,LP.LoginName,LP.DatabaseUser,LP.DBname , LP.RoleName

FROM  staging.dbo.Loginslist   sLP 

LEFT JOIN #LoginPermissions LP

ON LP.DBname = sLP.DBname

AND LP.LoginName = sLP.LoginName

AND LP.DatabaseUser = sLP.DatabaseUser

AND LP.RoleName = sLP.RoleName

ORDER BY sLP.LoginName,sLP.DatabaseUser,sLP.DBname , sLP.RoleName


SELECT LP.LoginName,LP.DatabaseUser,LP.DBname , LP.RoleName,

 sLP.LoginName,sLP.DatabaseUser,sLP.DBname , sLP.RoleName

FROM  #LoginPermissions LP

LEFT JOIN staging.dbo.Loginslist   sLP  

ON LP.DBname = sLP.DBname

AND LP.LoginName = sLP.LoginName

AND LP.DatabaseUser = sLP.DatabaseUser

AND LP.RoleName = sLP.RoleName

ORDER BY LP.LoginName,LP.DatabaseUser,LP.DBname , LP.RoleName



--SELECT * FROM staging.dbo.Loginslist 

Friday, 6 March 2026

SQLDBA - Get Space Used by Tables and Indexes in SQL Server

 Get Space Used by Tables and Indexes in SQL Server

Databases can consume significant amounts of storage, so it’s important to understand how that space is distributed across tables and indexes. SQL Server provides system views and metadata that allow us to query detailed storage information and generate reports at varying levels of granularity.

In this article, I will demonstrate several useful queries along with alternative methods for analyzing storage usage, helping you identify how space is allocated within your database and where optimization opportunities may exist.

What requires storage space?

A SQL Server database consists of several components, and its total size includes the actual data, transaction log data, and additional reserved space allocated for future growth. The data is stored in a primary data file (.mdf), optional secondary data files (.ndf), and at least one transaction log file (.ldf). For more information, you can refer to Microsoft’s documentation on database files and filegroups.

Data within the database is organized into tables and indexes.

  • A table may be stored as a heap or have a clustered index, which contains all the table’s data.
  • Nonclustered indexes are separate copies of the data designed to improve query performance but also consume storage.
  • Indexed views can also use storage space.
  • SQL Server also maintains IAM (Index Allocation Map) pages, which track how extents are allocated to objects.

SQL Server structures data using pages and extents:

  • Every page is 8 KB in size and is the fundamental unit of data storage.
  • An extent consists of eight contiguous pages, totaling 64 KB.
    These structures ensure efficient allocation and management of data inside the database.


Getting storage sizes from properties with SSMS

A simple way to view the total size of a database in SQL Server is through SQL Server Management Studio (SSMS).
By right‑clicking the database in Object Explorer and selecting Properties, you can see the Size and Space Available values on the General page.

The Files page provides a detailed list of all database files, including the reserved size for each file.

For individual tables, you can open the table’s Properties window and navigate to the Storage page. There, you will find the Data Space and Index Space values, which show how much storage the table’s data and indexes consume.


Using SSMS Reports

SQL Server Management Studio also offers reports to get the storage size of tables. These can be accessed by right clicking on a database and then go to “Reports”. The most interesting report is “Disk Usage by Table” which uses the following SQL query:


SELECT

    (row_number() over(order by a3.name, a2.name)) % 2 as l1,

    a3.name AS [schemaname],

    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

The data is read from the sys.dm_db_partition_stats view. The LFET JOIN with the sub query is used to get the size for columns with the xml type.


The result shows the count of rows, the reserved size for the whole table (or indexed view), the size of the data (this is the size of the cluster index or heap without the indexes), the size of all indexes including xml columns and the size of unused space.


Using sp_spaceused

sp_spaceused is a stored procedure to get the size of an object. You can either provide the name of a table or nothing to get the size of the whole database.


The @updateusage parameter with the value 'true' will run DBCC UPDATEUSAGE for the given object or the whole database. This can be used to update the stats, since the stats are not guaranteed to be up to date.


-- show the storage space of the whole database

EXECUTE sp_spaceused

-- show the storage space of a single table

EXECUTE sp_spaceused 'Person.Address'

-- update the stats for the given table and show the storage space

EXECUTE sp_spaceused 'Person.Address', 'true'

Getting file sizes with SQL query

The sys.database_files view contains all files of the selected database. The table contains the count of pages per file and in combination with the FILEPROPERTY function and 'SpaceUsed' argument we can get the used pages. By multiplying the count of pages with 8 we get the kilobytes. The final query looks like this:

SELECT

    F.file_id AS FileId,

    F.type_desc AS FileType,

    F.name AS FileName,

    F.physical_name AS PhysicalFileName,

    CASE WHEN F.max_size <= 0 THEN -1 ELSE CAST(CAST(F.max_size AS DECIMAL(18, 2)) * 8 / 1024 AS DECIMAL(18, 2)) END AS MaxSizeMb,

    CAST(CAST(F.size AS DECIMAL(18, 2)) * 8 / 1024 AS DECIMAL(18, 2)) AS TotalMb,

    CAST(CAST(FILEPROPERTY(F.name, 'SpaceUsed') AS DECIMAL(18, 2)) * 8 / 1024 AS DECIMAL(18, 2)) AS UsedMb,

    CAST(CAST((F.size - FILEPROPERTY(F.name, 'SpaceUsed')) AS DECIMAL(18, 2)) * 8 / 1024 AS DECIMAL(18, 2)) AS UnusedMb

FROM sys.database_files AS F

Getting index sizes with SQL query

The sys.allocation_units view contains the allocations in the partitions (container_id). It has a column for the total pages and one for the used pages. The view can be joined with sys.partitions to get the index it belongs to.

The sys.partitions view does contain the allocations by index, the sys.dm_db_partition_stats view, which is used by the “Disk Usage by Table”, is only for tables.

The final query looks like this:

SELECT

    S.name AS SchemaName,

    T.name AS TableName,

    ISNULL(I.name, '') AS IndexName,

    T.object_id AS TableObjectId,

    T.type_desc AS TableType,

    I.index_id AS IndexId,

    I.type_desc AS IndexType,

    A.Rows AS Rows,

    A.TotalPages + ISNULL(X.XmlTotalPages, 0) AS TotalPages,

    A.UsedPages + ISNULL(X.XmlUsedPages, 0) AS UsedPages,

    (A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS UnusedPages,

    (A.TotalPages + ISNULL(X.XmlTotalPages, 0)) * 8 AS TotalKb,

    (A.UsedPages + ISNULL(X.XmlUsedPages, 0)) * 8 AS UsedKb,

    ((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0))) * 8 AS UnusedKb,

    CAST(CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS TotalMb,

    CAST(CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS UsedMb,

    CAST(CAST(((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0))) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS UnusedMb,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS DECIMAL(18, 4)) / CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) * 100

         END AS DECIMAL(18, 4)) AS PercentUsed,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 100 - (CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS DECIMAL(18, 4)) / CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) * 100)

         END AS DECIMAL(18, 4)) AS PercentUnused,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) / SUM(CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4))) OVER() * 100

         END AS DECIMAL(18, 4)) AS PercentFromTotal

FROM sys.objects AS T

    INNER JOIN sys.schemas AS S ON S.schema_id = T.schema_id

    INNER JOIN sys.indexes AS I ON I.object_id = T.object_id

    INNER JOIN (SELECT

                    PA.object_id,

                    PA.index_id,

                    SUM(CASE WHEN AU.type_desc = 'IN_ROW_DATA' THEN PA.rows ELSE 0 END) AS Rows,

                    SUM(AU.total_pages) AS TotalPages,

                    SUM(AU.used_pages) AS UsedPages

                FROM sys.allocation_units AS AU

                    INNER JOIN sys.partitions AS PA ON PA.partition_id = AU.container_id

                GROUP BY PA.object_id, PA.index_id

               ) AS A ON A.object_id = I.object_id AND A.index_id = I.index_id

    LEFT JOIN (SELECT

                   IT.parent_id,

                   SUM(AU.total_pages) AS XmlTotalPages,

                   SUM(AU.used_pages) AS XmlUsedPages

               FROM sys.allocation_units AS AU

                   INNER JOIN sys.partitions AS PA ON PA.partition_id = AU.container_id

                   INNER JOIN sys.internal_tables AS IT ON IT.object_id = PA.object_id

               WHERE IT.internal_type_desc = 'XML_INDEX_NODES'

               GROUP BY IT.parent_id

              ) AS X ON X.parent_id = T.object_id AND I.type_desc IN ('HEAP', 'CLUSTERED')

WHERE T.type_desc IN ('USER_TABLE', 'VIEW')

ORDER BY PercentFromTotal DESC, S.name ASC, T.name ASC, I.index_id ASC

The result does contain the storage sizes in different units and percentages. The xml columns are appended to the clustered index or heap. Indexes on views are also included in the result. The PercentFromTotal column can be used to identify big tables or indexes in the database.


Getting table sizes with SQL query

The query for the indexes is the basis for the table size query. The grouping by index is removed in the allocations sub query and the xml size is appended to the entire table:


SELECT

    S.name AS SchemaName,

    T.name AS TableName,

    T.object_id AS TableObjectId,

    T.type_desc AS TableType,

    A.Rows AS Rows,

    A.TotalPages + ISNULL(X.XmlTotalPages, 0) AS TotalPages,

    A.UsedPages + ISNULL(X.XmlUsedPages, 0) AS UsedPages,

    (A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS UnusedPages,

    (A.TotalPages + ISNULL(X.XmlTotalPages, 0)) * 8 AS TotalKb,

    (A.UsedPages + ISNULL(X.XmlUsedPages, 0)) * 8 AS UsedKb,

    ((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0))) * 8 AS UnusedKb,

    CAST(CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS TotalMb,

    CAST(CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS UsedMb,

    CAST(CAST(((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) - (A.UsedPages + ISNULL(X.XmlUsedPages, 0))) * 8 AS DECIMAL(18, 4)) / 1024 AS DECIMAL(18, 4)) AS UnusedMb,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS DECIMAL(18, 4)) / CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) * 100

         END AS DECIMAL(18, 4)) AS PercentUsed,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 100 - (CAST((A.UsedPages + ISNULL(X.XmlUsedPages, 0)) AS DECIMAL(18, 4)) / CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) * 100)

         END AS DECIMAL(18, 4)) AS PercentUnused,

    CAST(CASE

             WHEN A.TotalPages + ISNULL(X.XmlTotalPages, 0) = 0 THEN

                 0

             ELSE

                 CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4)) / SUM(CAST((A.TotalPages + ISNULL(X.XmlTotalPages, 0)) AS DECIMAL(18, 4))) OVER() * 100

         END AS DECIMAL(18, 4)) AS PercentFromTotal

FROM sys.objects AS T

    INNER JOIN sys.schemas AS S ON S.schema_id = T.schema_id

    INNER JOIN (SELECT

                    PA.object_id,

                    SUM(CASE WHEN AU.type_desc = 'IN_ROW_DATA' AND PA.index_id IN (0, 1) THEN PA.rows ELSE 0 END) AS Rows,

                    SUM(AU.total_pages) AS TotalPages,

                    SUM(AU.used_pages) AS UsedPages

                FROM sys.allocation_units AS AU

                    INNER JOIN sys.partitions AS PA ON PA.partition_id = AU.container_id

                GROUP BY PA.object_id

               ) AS A ON A.object_id = T.object_id

    LEFT JOIN (SELECT

                   IT.parent_id,

                   SUM(AU.total_pages) AS XmlTotalPages,

                   SUM(AU.used_pages) AS XmlUsedPages

               FROM sys.allocation_units AS AU

                   INNER JOIN sys.partitions AS PA ON PA.partition_id = AU.container_id

                   INNER JOIN sys.internal_tables AS IT ON IT.object_id = PA.object_id

               WHERE IT.internal_type_desc = 'XML_INDEX_NODES'

               GROUP BY IT.parent_id

              ) AS X ON X.parent_id = T.object_id

WHERE T.type_desc IN ('USER_TABLE', 'VIEW')

ORDER BY PercentFromTotal DESC, S.name ASC, T.name ASC


DBAs: Check Out the New Features in SQL Server 2025 (17.x)

  DBAs: Check Out the New Features in SQL Server 2025 (17.x) Microsoft SQL Server 2025 introduces several enhancements that are especially r...