Thursday, April 29, 2021

Database performance information

Understanding Your SQL Server Databases: A Comprehensive Query

This post provides a powerful SQL query to gather crucial information about all databases on your SQL Server instance. You'll get insights into their **recovery model**, **log reuse wait description**, **log file size**, **log usage size**, and **compatibility level**, along with many other important database settings. This script is invaluable for monitoring database health and performance.


SELECT db.[name] AS [Database Name]
 ,SUSER_SNAME(db.owner_sid) AS [Database Owner]
 ,db.recovery_model_desc AS [Recovery Model]
 ,db.state_desc
 ,db.containment_desc
 ,db.log_reuse_wait_desc AS [Log Reuse Wait Description]
 ,CONVERT(DECIMAL(18, 2), ls.cntr_value / 1024.0) AS [Log Size (MB)]
 ,CONVERT(DECIMAL(18, 2), lu.cntr_value / 1024.0) AS [Log Used (MB)]
 ,CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT) AS DECIMAL(18, 2)) * 100 AS [Log Used %]
 ,db.[compatibility_level] AS [DB Compatibility Level]
 ,db.is_mixed_page_allocation_on
 ,db.page_verify_option_desc AS [Page Verify Option]
 ,db.is_auto_create_stats_on
 ,db.is_auto_update_stats_on
 ,db.is_auto_update_stats_async_on
 ,db.is_parameterization_forced
 ,db.snapshot_isolation_state_desc
 ,db.is_read_committed_snapshot_on
 ,db.is_auto_close_on
 ,db.is_auto_shrink_on
 ,db.target_recovery_time_in_seconds
 ,db.is_cdc_enabled
 ,db.is_published
 ,db.is_distributor
 ,db.group_database_id
 ,db.replica_id
 ,db.is_memory_optimized_elevate_to_snapshot_on
 ,db.delayed_durability_desc
 ,db.is_auto_create_stats_incremental_on
 ,db.is_query_store_on
 ,db.is_sync_with_backup
 ,db.is_temporal_history_retention_enabled
 ,db.is_supplemental_logging_enabled
 ,db.is_remote_data_archive_enabled
 ,db.is_encrypted
 ,de.encryption_state
 ,de.percent_complete
 ,de.key_algorithm
 ,de.key_length
 ,db.resource_pool_id
 ,db.is_tempdb_spill_to_remote_store
 ,db.is_result_set_caching_on
 ,db.is_accelerated_database_recovery_on
 ,is_stale_page_detection_on
FROM sys.databases AS db WITH (NOLOCK)
INNER JOIN sys.dm_os_performance_counters AS lu WITH (NOLOCK) ON db.name = lu.instance_name
INNER JOIN sys.dm_os_performance_counters AS ls WITH (NOLOCK) ON db.name = ls.instance_name
LEFT OUTER JOIN sys.dm_database_encryption_keys AS de WITH (NOLOCK) ON db.database_id = de.database_id
WHERE lu.counter_name LIKE N'Log File(s) Used Size (KB)%'
 AND ls.counter_name LIKE N'Log File(s) Size (KB)%'
 AND ls.cntr_value > 0
ORDER BY db.[name]
OPTION (RECOMPILE);

This query leverages two key Dynamic Management Views (DMVs) for its data:


Sunday, April 25, 2021

Find all comments in SQL server for all kind of objects

This post details how to retrieve records using extended properties within your SQL Server database. The following SQL scripts demonstrate how to query various database objects for their associated extended properties.

Objects and Columns

SELECT 
  CASE 
    WHEN ob.parent_object_id > 0
    THEN OBJECT_SCHEMA_NAME(ob.parent_object_id) + '.' + OBJECT_NAME(ob.parent_object_id) + '.' + ob.name
    ELSE OBJECT_SCHEMA_NAME(ob.object_id) + '.' + ob.name
  END + CASE 
    WHEN ep.minor_id > 0
    THEN '.' + col.name
    ELSE ''
  END AS path
  ,'schema' + CASE 
    WHEN ob.parent_object_id > 0
    THEN '/table'
    ELSE ''
  END + '/' + CASE 
    WHEN ob.type IN (
      'TF'
      ,'FN'
      ,'IF'
      ,'FS'
      ,'FT'
      )
    THEN 'function'
    WHEN ob.type IN (
      'P'
      ,'PC'
      ,'RF'
      ,'X'
      )
    THEN 'procedure'
    WHEN ob.type IN (
      'U'
      ,'IT'
      )
    THEN 'table'
    WHEN ob.type = 'SQ'
    THEN 'queue'
    ELSE LOWER(ob.type_desc)
  END + CASE 
    WHEN col.column_id IS NULL
    THEN ''
    ELSE '/column'
  END AS thing
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.objects ob ON ep.major_id = ob.OBJECT_ID
  AND class = 1
LEFT OUTER JOIN sys.columns col ON ep.major_id = col.Object_id
  AND class = 1
  AND ep.minor_id = col.column_id

Indexes

SELECT --indexes
  OBJECT_SCHEMA_NAME(ob.object_id) + '.' + OBJECT_NAME(ob.object_id) + '.' + ix.name
  ,'schema/' + LOWER(ob.type_desc) + '/index'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.objects ob ON ep.major_id = ob.OBJECT_ID
  AND class = 7
INNER JOIN sys.indexes ix ON ep.major_id = ix.Object_id
  AND class = 7
  AND ep.minor_id = ix.index_id

Parameters

SELECT --Parameters
  OBJECT_SCHEMA_NAME(ob.object_id) + '.' + OBJECT_NAME(ob.object_id) + '.' + par.name
  ,'schema/' + LOWER(ob.type_desc) + '/parameter'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.objects ob ON ep.major_id = ob.OBJECT_ID
  AND class = 2
INNER JOIN sys.parameters par ON ep.major_id = par.Object_id
  AND class = 2
  AND ep.minor_id = par.parameter_id

Schemas

SELECT --schemas
  sch.name
  ,'schema'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.schemas sch ON class = 3
  AND ep.major_id = SCHEMA_ID

Database

SELECT DB_NAME()
  ,''
  ,ep.name
  ,value
FROM sys.extended_properties ep
WHERE class = 0

XML Schema Collections

SELECT SCHEMA_NAME(SCHEMA_ID) + '.' + XC.name
  ,'schema/xml_Schema_collection'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.xml_schema_collections xc ON class = 10
  AND ep.major_id = xml_collection_id

Database Files

SELECT --Database Files
  df.name
  ,'database_file'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.database_files df ON class = 22
  AND ep.major_id = file_id

Data Spaces

SELECT --Data Spaces
  ds.name
  ,'dataspace'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.data_spaces ds ON class = 20
  AND ep.major_id = data_space_id

Users

SELECT --USER
  dp.name
  ,'database_principal'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.database_principals dp ON class = 4
  AND ep.major_id = dp.principal_id

Partition Function

SELECT --PARTITION FUNCTION
  pf.name
  ,'partition_function'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.partition_functions pf ON class = 21
  AND ep.major_id = pf.function_id

Remote Service Binding

SELECT --REMOTE SERVICE BINDING
  rsb.name
  ,'remote service binding'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.remote_service_bindings rsb ON class = 18
  AND ep.major_id = rsb.remote_service_binding_id

Route

SELECT --Route
  rt.name
  ,'route'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.routes rt ON class = 19
  AND ep.major_id = rt.route_id

Service

SELECT --Service
  sv.name COLLATE DATABASE_DEFAULT
  ,'service'
  ,ep.name
  ,value
FROM sys.extended_properties ep
INNER JOIN sys.services sv ON class = 17
  AND ep.major_id = sv.service_id

Contract

SELECT -- 'CONTRACT'
  svc.name
  ,'service_contract'
  ,ep.name
  ,value
FROM sys.service_contracts svc
INNER JOIN sys.extended_properties ep ON class = 16
  AND ep.major_id = svc.service_contract_id

Message Type

SELECT -- 'MESSAGE TYPE'
  smt.name
  ,'message_type'
  ,ep.name
  ,value
FROM sys.service_message_types smt
INNER JOIN sys.extended_properties ep ON class = 15
  AND ep.major_id = smt.message_type_id

Plan Guide

SELECT -- 'PLAN GUIDE' 
  pg.name
  ,'plan_guide'
  ,ep.name
  ,value
FROM sys.plan_guides pg
INNER JOIN sys.extended_properties ep ON class = 27
  AND ep.major_id = pg.plan_guide_id

Assembly

SELECT -- 'assembly'
  asy.name
  ,'assembly'
  ,ep.name
  ,value
FROM sys.assemblies asy
INNER JOIN sys.extended_properties ep ON class = 5
  AND ep.major_id = asy.assembly_id

Certificates, Asymmetric Keys, and Symmetric Keys

Note: The following SQL queries for Certificates, Asymmetric Keys, and Symmetric Keys require the `class` values to be filled in for accurate results. You can find these values in the reference table below.

--UNION ALL 
SELECT --'CERTIFICATE'
  cer.name,'certificate', ep.name,value 
FROM sys.certificates cer
INNER JOIN sys.extended_properties ep ON class=? AND ep.major_id=cer.certificate_id

UNION ALL --'ASYMMETRIC KEY'
 
SELECT amk.name,'asymmetric_key', ep.name,value  
FROM sys.asymmetric_keys amk
INNER JOIN sys.extended_properties ep ON class=? AND ep.major_id=amk.asymmetric_key_id

SELECT --'SYMMETRIC KEY'
  smk.name,'symmetric_key', ep.name,value 
FROM sys.symmetric_keys smk
INNER JOIN sys.services sv ON class=? AND ep.major_id=smk.symmetric_key_id 

Here's a table outlining the `class` values for different database items:

class tinyint Identifies the class of item on which the property exists. Can be one of the following:
0 = Database
1 = Object or column
2 = Parameter
3 = Schema
4 = Database principal
5 = Assembly
6 = Type
7 = Index
8 = User defined table type column
10 = XML schema collection
15 = Message type
16 = Service contract
17 = Service
18 = Remote service binding
19 = Route
20 = Dataspace (filegroup or partition scheme)
21 = Partition function
22 = Database file
27 = Plan guide

Additional Resources

For more detailed information, please refer to the following resources:

Sunday, April 18, 2021

Database documentation within a database

This post demonstrates how to add descriptive comments to SQL Server database objects using SQL scripts. These comments help document your database structure and provide context to developers and analysts.

How to Comment on a Table in SQL Server

-- Add a description to a table
EXEC sys.sp_addextendedproperty   
 @name = N'MS_Description', 
 @value = N'Contains customer-related data.',   
 @level0type = N'SCHEMA',    
 @level0name = 'dbo',  
 @level1type = N'TABLE',     
 @level1name = 'tblCustomer';  
GO

Now let's see how to add a comment to a specific column within a table.

-- Add a description to a column
EXEC sp_addextendedproperty   
 @name  = N'MS_Description',
 @value = 'Primary key identifier for the customer.',  
 @level0type = N'Schema',  
 @level0name = 'dbo',  
 @level1type = N'Table',   
 @level1name = 'tblCustomer',   
 @level2type = N'Column',  
 @level2name = 'CustomerID';  
GO

For more in-depth guidance on querying all existing comments across SQL Server objects, visit the reference below:

Find All Comments in SQL Server – Himanshu Patel

Saturday, April 17, 2021

Foreign Key scripts

It's helpful to maintain ready-to-use scripts for resetting database contents, including reseeding identities. Feel free to adjust these scripts to fit your specific needs.

Drop Temporary Table

IF OBJECT_ID('tempdb..#Fkey') IS NOT NULL
    DROP TABLE #Fkey;
  

Create Temporary Table with Foreign Key Information

;WITH cte AS (
    SELECT 
        fkc.constraint_column_id AS consColumn,
        fk.NAME AS foreignKeyName,
        parentSchema.name AS parentSchema,
        parentTable.NAME AS parentTableName,
        parent_col.NAME AS parentColName,
        refSchema.name AS refSchema,
        refTable.NAME AS refTableName,
        ref_col.NAME AS refColName
    FROM sys.foreign_keys fk
    INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.tables parentTable ON parentTable.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas parentSchema ON parentSchema.schema_id = parentTable.schema_id
    INNER JOIN sys.columns parent_col ON fkc.parent_column_id = parent_col.column_id AND parent_col.object_id = parentTable.object_id
    INNER JOIN sys.tables refTable ON refTable.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas refSchema ON refSchema.schema_id = refTable.schema_id
    INNER JOIN sys.columns ref_col ON fkc.referenced_column_id = ref_col.column_id AND ref_col.object_id = refTable.object_id
    WHERE parentTable.type = 'U' AND refTable.type = 'U'
)
SELECT DISTINCT 
    foreignKeyName,
    parentSchema,
    parentTableName,
    SUBSTRING((
        SELECT ',' + a.parentColName
        FROM cte a
        WHERE a.foreignKeyName = c.foreignKeyName
        ORDER BY a.consColumn
        FOR XML PATH('')
    ), 2, 300000) AS parentColName,
    refSchema,
    refTableName,
    SUBSTRING((
        SELECT ',' + b.refColName
        FROM cte b
        WHERE b.foreignKeyName = c.foreignKeyName
        ORDER BY b.consColumn
        FOR XML PATH('')
    ), 2, 300000) AS refColName
INTO #Fkey
FROM cte c;
  

Generate Scripts to Drop Foreign Keys

-- Generate scripts to drop existing foreign key constraints
SELECT DISTINCT 
    'IF EXISTS (SELECT * FROM sys.foreign_keys 
        WHERE object_id = OBJECT_ID(N''[' + parentSchema + '].[' + foreignKeyName + ']'') 
        AND parent_object_id = OBJECT_ID(N''[' + parentSchema + '].[' + ParentTableName + ']''))
    ALTER TABLE [' + parentSchema + '].[' + ParentTableName + '] DROP CONSTRAINT [' + foreignKeyName + ']' 
AS foreignKey_drop_script
FROM #Fkey;
  

Generate Scripts to Recreate Foreign Keys

-- Generate scripts to recreate the foreign key constraints
SELECT DISTINCT 
    'ALTER TABLE [' + parentSchema + '].[' + ParentTableName + '] WITH CHECK 
    ADD CONSTRAINT [' + foreignKeyName + '] FOREIGN KEY(' + parentColName + ') 
    REFERENCES [' + refSchema + '].[' + refTableName + '](' + refColName + ')' 
AS Add_constraints_script
FROM #Fkey;
GO
  

Additional Resources:

Sunday, April 11, 2021

Database Snapshots (SQL Server)

Starting with SQL Server 2016 SP1, all editions now support the database snapshot feature.

A database snapshot provides a static, read-only image of a SQL Server database at a specific point in time. This snapshot remains transactionally consistent with the source database as it existed at the moment the snapshot was taken. Note that the snapshot must reside on the same server instance as its original database.


CREATE DATABASE <database_snapshot_name>
ON (
  NAME = <logical_file_name>, FILENAME = '<os_file_name>'
) [ ,...n ]
AS SNAPSHOT OF <source_database_name>
  

Note: The .ss file extension shown in the examples is user-defined and not mandatory.


CREATE DATABASE AdventureWorks_dbss1800 ON  
( NAME = AdventureWorks, FILENAME =  
'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data\AdventureWorks_data_1800.ss' )  
AS SNAPSHOT OF AdventureWorks;  
GO
  

Restoring the Original Database Using a Snapshot


RESTORE DATABASE <database_name> 
FROM DATABASE_SNAPSHOT = <database_snapshot_name>
  

Further Reading:

Saturday, April 10, 2021

SSIS CSV Import error when a special character in the text column

If you encounter issues importing a CSV file using an SSIS package—particularly when strings are enclosed in double quotes—here’s a method you can try to fix the problem.

Sample CSV Data

"090","Grey",""
"091","Grey, Red",""
"092","White/Teal",""
"042","Blue ","(\"is not blue\" )"    --- TextQualified '"' with single quote inside value
"093","Light Grey",""

Error Message:
[SSIS.Pipeline] Error: SSIS Error Code DTS_E_PRIMEOUTPUTFAILED. The PrimeOutput method on Flat File Source returned error code 0xC0202092. This error is fatal and stops pipeline execution. Additional error details might be available earlier in the log.

To fix this, review the column settings in the Flat File Connection Manager:

Steps:
Navigate to Flat File Connection Manager → Advanced Tab and review the column properties.

Flat File Connection Manager settings

Set TextQualified to false.

TextQualified property setting

Now, attempt to import the CSV file again. The issue should be resolved.

Sunday, April 4, 2021

Pivot table

Below is the general syntax used when working with the PIVOT operator in SQL. This technique transforms rows into columns to better analyze aggregated data.

SELECT <non-pivoted column>,  
    [first pivoted column] AS <column name>,  
    [second pivoted column] AS <column name>,  
    ...  
    [last pivoted column] AS <column name>  
FROM  
    (<SELECT query that retrieves the data>) AS <source alias>  
PIVOT  
(  
    <aggregate function>(<column to aggregate>)  
    FOR [<column with values to become headers>]  
    IN ([first pivoted column], [second pivoted column], ..., [last pivoted column])  
) AS <pivot table alias>  
<optional ORDER BY clause>;

Example: Basic PIVOT Query

-- This example creates a pivot table with one row and five columns
SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days,  
[0], [1], [2], [3], [4]  
FROM  
(SELECT DaysToManufacture, StandardCost FROM Production.Product) AS SourceTable  
PIVOT  
(  
AVG(StandardCost)  
FOR DaysToManufacture IN ([0], [1], [2], [3], [4])  
) AS PivotTable;

Advanced PIVOT Example

USE AdventureWorks2014;  
GO  
SELECT VendorID, [250] AS Emp1, [251] AS Emp2, [256] AS Emp3, [257] AS Emp4, [260] AS Emp5  
FROM  
(SELECT PurchaseOrderID, EmployeeID, VendorID FROM Purchasing.PurchaseOrderHeader) AS p  
PIVOT  
(  
COUNT(PurchaseOrderID)  
FOR EmployeeID IN ([250], [251], [256], [257], [260])  
) AS pvt  
ORDER BY pvt.VendorID;

Example: UNPIVOT Operation

-- Creating the base table and inserting sample values
CREATE TABLE pvt (
    VendorID INT, 
    Emp1 INT, 
    Emp2 INT, 
    Emp3 INT, 
    Emp4 INT, 
    Emp5 INT
);  
GO  

INSERT INTO pvt VALUES (1,4,3,5,4,4);  
INSERT INTO pvt VALUES (2,4,1,5,5,5);  
INSERT INTO pvt VALUES (3,4,3,5,4,4);  
INSERT INTO pvt VALUES (4,4,2,5,5,4);  
INSERT INTO pvt VALUES (5,5,1,5,5,5);  
GO  

-- Applying the UNPIVOT operator
SELECT VendorID, Employee, Orders  
FROM  
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5 FROM pvt) AS p  
UNPIVOT  
(Orders FOR Employee IN (Emp1, Emp2, Emp3, Emp4, Emp5)) AS unpvt;  
GO

Popular Posts