<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQLpowered.com</title>
	<atom:link href="https://sqlpowered.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://sqlpowered.com</link>
	<description>SQL Server + BI</description>
	<lastBuildDate>Tue, 17 Feb 2026 22:59:05 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://sqlpowered.com/wp-content/uploads/2020/07/FavIcon-e1594067873682-99x100.png</url>
	<title>SQLpowered.com</title>
	<link>https://sqlpowered.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>JSON Data Type Is Not Comparable!</title>
		<link>https://sqlpowered.com/json-data-type-is-not-comparable/</link>
					<comments>https://sqlpowered.com/json-data-type-is-not-comparable/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Tue, 17 Feb 2026 22:47:49 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5802</guid>

					<description><![CDATA[I was really not happy when I hit this with the new JSON data type. In SQL Server, set operators like UNION, INTERSECT, and EXCEPT have been a very reliable part of many generic scripts. We already survived older non-comparable types like text and image, and things became much cleaner...]]></description>
										<content:encoded><![CDATA[<p>I was really not happy when I hit this with the new <code>JSON</code> data type. In SQL Server, set operators like <code>UNION</code>, <code>INTERSECT</code>, and <code>EXCEPT</code> have been a very reliable part of many generic scripts. We already survived older non-comparable types like <code>text</code> and <code>image</code>, and things became much cleaner after moving away from them. But now <code>JSON</code> brings a very similar problem back. Even if both sides have the same column type, SQL Server still refuses to compare it in set operators.</p>
<p>Quick reminder: these operators need values that SQL Server can compare to detect duplicates and matches. If a data type is non-comparable, generic set-based scripts break immediately unless you cast. Most common troublemakers are legacy LOB types (<code>text</code>, <code>ntext</code>, <code>image</code>), and also <code>xml</code> in many compare/sort scenarios. And the new <code>json</code> since SQL Server 2025. So this is not only about one edge case, it is a design concern for reusable SQL tooling.</p>
<p>This is the simple repro:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DROP TABLE IF EXISTS [dbo].[TableA]
DROP TABLE IF EXISTS [dbo].[TableB]

CREATE TABLE [dbo].[TableA] (
    [JSON_Data] JSON
)

CREATE TABLE [dbo].[TableB] (
    [JSON_Data] JSON
)

SELECT * FROM [dbo].[TableA]
UNION
SELECT * FROM [dbo].[TableB]
GO
</pre>
<p>It fails with this SQL Server error:</p>
<pre style="color: #c00000;">Msg 5335, Level 16, State 1, Line 14
The data type json cannot be used as an operand to the UNION, INTERSECT or EXCEPT operators because it is not comparable.
</pre>
<p>That means generic scripts now need special handling whenever any source column is <code>JSON</code>.</p>
<p>Current practical fix is explicit cast:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT CAST([JSON_Data] AS NVARCHAR(MAX)) FROM [dbo].[TableA]
UNION
SELECT CAST([JSON_Data] AS NVARCHAR(MAX)) FROM [dbo].[TableB]
GO
</pre>
<p>This works, but it also means more branching and more complexity in reusable SQL utilities. In practice, any metadata-driven script should detect non-comparable source types and auto-cast them to a comparable string/binary representation before applying set operators.</p>
<p><strong>Note</strong>: Microsoft already added one <code>json</code> data type column in a new system view <code>sys.external_models</code> in SQL Server 2025. Check this query:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT [o].[name], [c].[name], [tp].[name]
FROM [sys].[system_objects] [o]
	INNER JOIN [sys].[system_columns] [c] ON [c].[object_id] = [o].[object_id]
	INNER JOIN [sys]. [tp] ON [tp].[system_type_id] = [c].[system_type_id] AND [tp].[user_type_id] = [c].[user_type_id]
WHERE [tp].[name] = 'json'
</pre>
<p><img fetchpriority="high" decoding="async" class="alignnone  wp-image-5804" src="https://sqlpowered.com/wp-content/uploads/2026/02/sys_external_models_json.png" alt="" width="355" height="309" srcset="https://sqlpowered.com/wp-content/uploads/2026/02/sys_external_models_json.png 553w, https://sqlpowered.com/wp-content/uploads/2026/02/sys_external_models_json-300x261.png 300w, https://sqlpowered.com/wp-content/uploads/2026/02/sys_external_models_json-115x100.png 115w, https://sqlpowered.com/wp-content/uploads/2026/02/sys_external_models_json-360x313.png 360w" sizes="(max-width: 355px) 100vw, 355px" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/json-data-type-is-not-comparable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SET vs SELECT Variable Assignment When No Rows Match</title>
		<link>https://sqlpowered.com/set-vs-select-variable-assignment-when-no-rows-match/</link>
					<comments>https://sqlpowered.com/set-vs-select-variable-assignment-when-no-rows-match/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 15 Feb 2026 21:15:34 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5476</guid>

					<description><![CDATA[This one can be easy to miss, but it can change your logic in a silent way. SET and SELECT look similar when assigning a variable, but they do not behave the same in all cases. The difference appears when the subquery returns no rows. With SELECT @var = ...the...]]></description>
										<content:encoded><![CDATA[<p>This one can be easy to miss, but it can change your logic in a silent way. <code>SET</code> and <code>SELECT</code> look similar when assigning a variable, but they do not behave the same in all cases. The difference appears when the subquery returns no rows. With <code>SELECT @var = ...</code>the variable keeps its previous value. With <code>SET @var = (SELECT ...)</code>the variable becomes <code>NULL</code>.</p>
<p>I tested it with a very small demo below. The query searching for <code>Id = 4</code> returns no row, because the table has only <code>1,2,3</code>. After that, <code>SELECT</code> leaves <code>@Id</code> as <code>10</code>, while <code>SET</code> changes it to <code>NULL</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DROP TABLE IF EXISTS #tmp
CREATE TABLE #tmp
(
    Id INT NOT NULL PRIMARY KEY
)

INSERT INTO #tmp (Id)
SELECT *
FROM (VALUES (1), (2), (3)) a(n)

DECLARE @Id INT

SET @Id = 10

-- SELECT
SELECT @Id = Id FROM #tmp WHERE Id = 4

SELECT @Id AS [SELECT]

-- SET
SET @Id = (SELECT Id FROM #tmp WHERE Id = 4)

SELECT @Id AS [SET]
</pre>
<p><img decoding="async" class="alignnone wp-image-5522" src="https://sqlpowered.com/wp-content/uploads/2023/02/SET_vs_SELECT_When_Assignin_Variable.png" alt="" width="96" height="88" srcset="https://sqlpowered.com/wp-content/uploads/2023/02/SET_vs_SELECT_When_Assignin_Variable.png 177w, https://sqlpowered.com/wp-content/uploads/2023/02/SET_vs_SELECT_When_Assignin_Variable-109x100.png 109w" sizes="(max-width: 96px) 100vw, 96px" /></p>
<p>Result in this test: <code>SELECT</code> gives <code>10</code>, <code>SET</code> gives <code>NULL</code>. So if &#8220;not found&#8221; should keep the old value, <code>SELECT</code> assignment can be useful. If &#8220;not found&#8221; should explicitly reset the variable, <code>SET</code> it gives you that behavior directly.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/set-vs-select-variable-assignment-when-no-rows-match/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server Allows Empty Stored Procedures</title>
		<link>https://sqlpowered.com/sql-server-allows-empty-stored-procedures/</link>
					<comments>https://sqlpowered.com/sql-server-allows-empty-stored-procedures/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 15 Feb 2026 21:06:52 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5725</guid>

					<description><![CDATA[I found one small SQL Server behavior that surprised me more than I expected. You can create a stored procedure with an empty body, and SQL Server will accept it. No SELECT, no INSERT, no PRINT, nothing inside. Even more surprisingly, the procedure can be executed without any error. I...]]></description>
										<content:encoded><![CDATA[<p>I found one small SQL Server behavior that surprised me more than I expected. You can create a stored procedure with an empty body, and SQL Server will accept it. No SELECT, no INSERT, no PRINT, nothing inside. Even more surprisingly, the procedure can be executed without any error. I always assumed at least one statement would be required, but apparently not.</p>
<p>This is not something you will usually use in real production logic, but it is a useful edge case to know. It helps when you test how SQL Server validates object definitions and execution flow.</p>
<p>Simple demo:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE PROCEDURE MyEmptyProcedure AS
GO

EXEC MyEmptyProcedure
GO</pre>
<p>So yes, it really works. The procedure body can be empty, and SQL Server still allows create + execute.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/sql-server-allows-empty-stored-procedures/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server 2025 vs 2022: What Changed in DMVs</title>
		<link>https://sqlpowered.com/sql-server-2025-vs-2022-what-changed-in-dmvs-download-the-comparison-report/</link>
					<comments>https://sqlpowered.com/sql-server-2025-vs-2022-what-changed-in-dmvs-download-the-comparison-report/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 18 Jan 2026 20:51:06 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5784</guid>

					<description><![CDATA[I recently compared SQL Server system DMVs between SQL Server 2022 (16.0.4225.2) and SQL Server 2025 (17.0.1000.7). I used Redgate SQL Compare to generate an HTML report, and in this post, I’m providing a summary of the changes made, including additions, deletions, and modifications. See the full comparison: SQL_2022_To_2025_DMV_Comparison How...]]></description>
										<content:encoded><![CDATA[<p>I recently compared SQL Server system DMVs between SQL Server 2022 (16.0.4225.2) and SQL Server 2025 (17.0.1000.7). I used Redgate SQL Compare to generate an HTML report, and in this post, I’m providing a summary of the changes made, including additions, deletions, and modifications.</p>
<p>See the full comparison: <a href="https://sqlpowered.com/wp-content/uploads/2026/01/SQL_2022_To_2025_DMV_Comparison.html">SQL_2022_To_2025_DMV_Comparison</a></p>
<h3>How I built the comparison list</h3>
<p>I exported the list of system views from the <code>sys</code> schema using the query below. I also filtered out anything under <code>INFORMATION_SCHEMA</code> because I wanted to focus on the “real” system catalog/DMV surface area.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT * 
FROM [sys].[system_objects] [so] 
    INNER JOIN [sys].[schemas] [sch] ON [sch].[schema_id] = [so].[schema_id] 
WHERE [type] = 'V' AND [sch].[name] = 'sys';</pre>
<h3>Headline numbers</h3>
<ul>
<li>Added: 28</li>
<li>Removed: 6</li>
<li>Modified: 39</li>
<li>Identical: 565</li>
</ul>
<p>These counts are straight from the SQL Compare report.</p>
<h3>New system objects in SQL Server 2025 (added)</h3>
<p>The most interesting additions fall into a few “themes”: newer query processing diagnostics, automatic tuning internals, memory/OS health visibility, governance/security metadata, and new metadata areas like JSON and vector indexing.</p>
<ul>
<li><code>sys_dm_database_backup_lineage</code></li>
<li><code>sys_dm_db_information_protection_label_properties</code></li>
<li><code>sys_dm_db_internal_auto_tuning_create_index_recommendations</code></li>
<li><code>sys_dm_db_internal_auto_tuning_recommendation_impact_query_metrics</code></li>
<li><code>sys_dm_db_internal_auto_tuning_recommendation_metrics</code></li>
<li><code>sys_dm_db_internal_auto_tuning_workflows</code></li>
<li><code>sys_dm_db_internal_automatic_tuning_version</code></li>
<li><code>sys_dm_db_logical_index_corruptions</code></li>
<li><code>sys_dm_db_xtp_undeploy_status</code></li>
<li><code>sys_dm_exec_ce_feedback_cache</code></li>
<li><code>sys_dm_exec_distributed_tasks</code></li>
<li><code>sys_dm_external_governance_synchronizing_objects</code></li>
<li><code>sys_dm_external_policy_excluded_role_members</code></li>
<li><code>sys_dm_hadr_internal_availability_groups</code></li>
<li><code>sys_dm_hadr_internal_availability_replicas</code></li>
<li><code>sys_dm_io_network_traffic_stats</code></li>
<li><code>sys_dm_os_memory_allocations_filtered</code></li>
<li><code>sys_dm_os_memory_health_history</code></li>
<li><code>sys_dm_os_memory_nodes_processor_groups</code></li>
<li><code>sys_dm_os_parent_block_descriptors</code></li>
<li><code>sys_dm_pal_ring_buffers</code></li>
<li><code>sys_dm_server_managed_identities</code></li>
<li><code>sys_external_models</code></li>
<li><code>sys_external_table_schema_changed_mdsync</code></li>
<li><code>sys_information_protection_label_mapping</code></li>
<li><code>sys_json_index_paths</code></li>
<li><code>sys_json_indexes</code></li>
<li><code>sys_vector_indexes</code></li>
</ul>
<h3>System objects that disappeared in SQL Server 2025 (removed)</h3>
<p>Only six objects were flagged as removed.</p>
<ul>
<li><code>sys_dm_dw_locks</code></li>
<li><code>sys_dm_pal_spinlock_stats</code></li>
<li><code>sys_dm_pal_wait_stats</code></li>
<li><code>sys_dm_toad_tuning_zones</code></li>
<li><code>sys_dm_toad_work_item_handlers</code></li>
<li><code>sys_dm_toad_work_items</code></li>
</ul>
<h3>Modified objects (what changed, at a high level)</h3>
<p>The report shows 39 modified objects. In practice, these changes are typically “column-level” updates to internal catalog tables and DMVs to support new features and diagnostics in SQL Server 2025.</p>
<ul>
<li><strong>Query processing and tuning:</strong> changes around query profiling and memory grants, plus new cardinality-estimation feedback exposure (<code>sys_dm_exec_ce_feedback_cache</code> is new, and related surfaces like <code>sys_dm_exec_query_memory_grants</code> show changes).</li>
<li><strong>Query Store &amp; plan feedback:</strong> system objects related to plan feedback/forcing locations are modified (<code>sys_query_store_plan_feedback</code>, <code>sys_query_store_plan_forcing_locations</code>).</li>
<li><strong>Availability groups / HADR:</strong> both catalog views and DMVs around AGs are modified (<code>sys_availability_groups</code>, <code>sys_dm_hadr_availability_replica_states</code>, <code>sys_dm_hadr_database_replica_states</code>), and there are new “internal” HADR DMVs in 2025 (listed above).</li>
<li><strong>Memory/OS internals:</strong> multiple <code>sys_dm_os_*</code> objects are modified, and new memory-health/history DMVs appear in 2025.</li>
<li><strong>Governance and labeling:</strong> new information protection label mapping and governance-sync related surfaces appear, and existing governance DMVs are modified (<code>sys_dm_external_governance_sync_state</code>, <code>sys_dm_database_external_governance_sync_state</code>).</li>
<li><strong>Core catalog internals:</strong> classic internal objects like <code>sys_all_columns</code>, <code>sys_columns</code>, <code>sys_parameters</code>, <code>sys_stats</code>, and “system_*” internals show updates, which is typical when a major version adds metadata flags and new engine behaviors.</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/sql-server-2025-vs-2022-what-changed-in-dmvs-download-the-comparison-report/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server 2025 Upgrade: Linked Servers May Fail Unless You Explicitly Set Encrypt</title>
		<link>https://sqlpowered.com/sql-server-2025-upgrade-gotcha-linked-servers-may-fail-unless-you-explicitly-set-encrypt/</link>
					<comments>https://sqlpowered.com/sql-server-2025-upgrade-gotcha-linked-servers-may-fail-unless-you-explicitly-set-encrypt/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 18 Jan 2026 10:19:07 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5778</guid>

					<description><![CDATA[When I migrated a set of linked servers from SQL Server 2022 to SQL Server 2025, a few of them started failing immediately during connection initialization. The root cause surprised me at first: SQL Server 2025 tightens the encryption defaults for linked servers, so a linked server that worked fine...]]></description>
										<content:encoded><![CDATA[<p>When I migrated a set of linked servers from SQL Server 2022 to SQL Server 2025, a few of them started failing immediately during connection initialization. The root cause surprised me at first: SQL Server 2025 tightens the encryption defaults for linked servers, so a linked server that worked fine on 2022 can fail on 2025 unless you explicitly define the encryption behavior in the provider string.</p>
<h3>What changed in SQL Server 2025</h3>
<ul>
<li>SQL Server 2025 introduces an encryption-related breaking change that can cause linked server connections to fail after an upgrade.</li>
<li>If the connection ends up requiring encryption with certificate validation, and the target server certificate isn’t trusted (or you connect by IP that doesn’t match the certificate name), the linked server can fail.</li>
<li>The quickest “get it working” mitigation I’ve used is to add <code>@provstr = N'Encrypt=Yes;TrustServerCertificate=yes'</code> when creating the linked server.</li>
<li>Best practice is still to use a proper CA-signed certificate and keep certificate validation enabled, but in real migrations you sometimes need the fast, pragmatic fix first.</li>
</ul>
<h3>SQL Server 2022 (working without explicit encryption settings)</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">USE [master]
GO

EXEC master.dbo.sp_addlinkedserver 
    @server = N'MyLinkedServer1', 
    @srvproduct = N'', 
    @provider = N'SQLNCLI', 
    @datasrc = N'123.123.123.123,1433'
GO</pre>
<h3>SQL Server 2025 script (explicit encryption in @provstr is required)</h3>
<p>On SQL Server 2025, adding an explicit provider string makes the intent clear and prevents the upgrade from breaking existing linked servers. I also recommend switching away from the legacy <code>SQLNCLI</code> provider to <code>MSOLEDBSQL</code> if you still have old scripts around.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-highlight="9">USE [master]
GO

EXEC master.dbo.sp_addlinkedserver 
    @server = N'MyLinkedServer1',
    @srvproduct = N'',
    @provider = N'MSOLEDBSQL',
    @datasrc = N'123.123.123.123,1433',
    @provstr = N'Encrypt=Yes;TrustServerCertificate=yes'
GO</pre>
<h3>References</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/sql/database-engine/breaking-changes-to-database-engine-features-in-sql-server-2025?view=sql-server-ver17">Database Engine breaking changes in SQL Server 2025 (linked server encryption)</a></li>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/linked-servers/linked-servers-database-engine?view=sql-server-ver17">Linked servers (Database Engine) – encryption defaults and Encrypt settings</a></li>
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addlinkedserver-transact-sql?view=sql-server-ver17">sp_addlinkedserver (Transact-SQL) – SQL Server 2025 notes on encrypt in @provstr</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/sql-server-2025-upgrade-gotcha-linked-servers-may-fail-unless-you-explicitly-set-encrypt/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SUBSTRING() in SQL Server 2022 vs 2025: Optional LENGTH Is Finally Here</title>
		<link>https://sqlpowered.com/substring-in-sql-server-2022-vs-2025-optional-length-is-finally-here/</link>
					<comments>https://sqlpowered.com/substring-in-sql-server-2022-vs-2025-optional-length-is-finally-here/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Fri, 16 Jan 2026 14:02:48 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5776</guid>

					<description><![CDATA[SUBSTRING() is one of those T-SQL functions we all use constantly: parsing identifiers, trimming prefixes, extracting parts of file paths, URLs, error messages, or just cleaning up data for reporting. Until now, SQL Server forced us to always provide the third argument (length). With SQL Server 2025, Microsoft added a...]]></description>
										<content:encoded><![CDATA[<p><code>SUBSTRING()</code> is one of those T-SQL functions we all use constantly: parsing identifiers, trimming prefixes, extracting parts of file paths, URLs, error messages, or just cleaning up data for reporting. Until now, SQL Server forced us to always provide the third argument (<code>length</code>).</p>
<p>With <strong>SQL Server 2025</strong>, Microsoft added a small but very practical improvement: <strong>the <code>length</code> parameter is now optional</strong>. If you omit it, SQL Server returns the substring from the start position to the end of the string.</p>
<p>See official doc: <a href="https://learn.microsoft.com/en-us/sql/t-sql/functions/substring-transact-sql?view=sql-server-ver17#e-use-substring-with-optional-length-argument" target="_blank" rel="noopener">SUBSTRING (Transact-SQL) – optional length argument</a>.</p>
<h2>Syntax comparison</h2>
<h3>SQL Server 2022 (and earlier)</h3>
<p>Length is required:</p>
<p><code class="EnlighterJSRAW" data-enlighter-language="sql">SUBSTRING(expression, start, length)</code></p>
<h3>SQL Server 2025</h3>
<p>Length can be omitted:</p>
<p><code class="EnlighterJSRAW" data-enlighter-language="sql">SUBSTRING(expression, start[, length])</code></p>
<h2>Practical T-SQL: 2022 vs 2025</h2>
<h3>Example 1: Extract everything after a prefix</h3>
<p>Let’s say you have a standard prefix and you want everything after it.</p>
<h4>SQL Server 2022</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @s varchar(100) = 'ENV:prod-west-eu'; 

-- Get everything after 'ENV:'
SELECT SUBSTRING(@s, 5, LEN(@s) - 4) AS tail_2022;</pre>
<h4>SQL Server 2025</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @s varchar(100) = 'ENV:prod-west-eu'; 

-- Get everything after 'ENV:' (length omitted) 
SELECT SUBSTRING(@s, 5) AS tail_2025;</pre>
<h3>Example 2: Split at a delimiter (common pattern)</h3>
<p>Extract everything after the first colon (:).</p>
<h4>SQL Server 2022</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @s varchar(100) = 'ServerName:SQL2022-01'; 

SELECT SUBSTRING(@s, CHARINDEX(':', @s) + 1, LEN(@s)) AS after_colon_2022;</pre>
<h4>SQL Server 2025</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @s varchar(100) = 'ServerName:SQL2025-01'; 

SELECT SUBSTRING(@s, CHARINDEX(':', @s) + 1) AS after_colon_2025;</pre>
<h2>One important detail: omitted vs NULL length</h2>
<p>The new behavior is triggered only when the third parameter is <strong>omitted</strong>. If you explicitly pass <code>NULL</code> as length, the result is still <code>NULL</code> (same as older versions).</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Same behavior (2022 and 2025): returns NULL because length is explicitly NULL
SELECT SUBSTRING('abc123', 4, NULL) AS returns_null;</pre>
<h2>Conclusion</h2>
<p>This change is small, but in daily T-SQL work it’s one of those “finally!” improvements. Anywhere you currently compute remaining length or use overshoot constants, SQL Server 2025 lets you write cleaner and more intention-revealing code.</p>
<p>If you’re maintaining scripts that must run on both SQL Server 2022 and 2025, <strong>keep the old 3-argument form for compatibility</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/substring-in-sql-server-2022-vs-2025-optional-length-is-finally-here/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server 2025 on Azure VM failed to deploy: “System Drive returned status not ready for use” (TempDB on uninitialized local NVMe)</title>
		<link>https://sqlpowered.com/sql-server-2025-on-azure-vm-failed-to-deploy-system-drive-returned-status-not-ready-for-use-tempdb-on-uninitialized-local-nvme/</link>
					<comments>https://sqlpowered.com/sql-server-2025-on-azure-vm-failed-to-deploy-system-drive-returned-status-not-ready-for-use-tempdb-on-uninitialized-local-nvme/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 11 Jan 2026 20:03:48 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5773</guid>

					<description><![CDATA[I recently encountered a deployment failure when provisioning a new SQL Server 2025 VM based on a Windows Server 2025 image in Azure. The VM size was E2ds_v6, which includes ~110 GB local storage (NVMe / ephemeral). The deployment failed during provisioning with this error: { "status": "Failed", "error": {...]]></description>
										<content:encoded><![CDATA[<p>I recently encountered a deployment failure when provisioning a new <strong>SQL Server 2025</strong> VM based on a <strong>Windows Server 2025</strong> image in Azure.</p>
<p><img decoding="async" class="alignnone wp-image-5775" src="https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq.png" alt="" width="540" height="240" srcset="https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq.png 1605w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-300x133.png 300w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-1024x455.png 1024w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-150x67.png 150w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-768x341.png 768w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-1536x682.png 1536w, https://sqlpowered.com/wp-content/uploads/2026/01/h1c033I2zq-360x160.png 360w" sizes="(max-width: 540px) 100vw, 540px" /></p>
<p>The VM size was <strong>E2ds_v6</strong>, which includes <strong>~110 GB local storage</strong> (NVMe / ephemeral).</p>
<p>The deployment failed during provisioning with this error:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="json">{
  "status": "Failed",
  "error": {
    "code": "Ext_StorageConfigurationSettings_ApplyNewTempDbSettingsError",
    "message": "Error: 'System Drive returned status not ready for use '"
}</pre>
<h2>What was happening</h2>
<p>In my case, the root cause was surprisingly simple: the local NVMe disk was presented to Windows as <strong>RAW / uninitialized</strong>.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5774" src="https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV.png" alt="" width="606" height="398" srcset="https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV.png 1669w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-300x197.png 300w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-1024x672.png 1024w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-150x100.png 150w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-768x504.png 768w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-1536x1009.png 1536w, https://sqlpowered.com/wp-content/uploads/2026/01/bZOpXyVglV-360x236.png 360w" sizes="auto, (max-width: 606px) 100vw, 606px" /></p>
<p>The <strong>SQL Server IaaS extension</strong> (the component Azure uses to apply storage configuration for SQL on a VM) tried to configure <strong>tempdb</strong> on that local disk. Because the disk had no partition, no file system, and no drive letter, the extension step failed, and the entire provisioning process ended as <strong>Failed</strong>.</p>
<p>This is especially annoying because local/ephemeral disks are exactly where you often want tempdb (fast IOPS), but only if the disk is actually usable at boot time.</p>
<h2>The fix: initialize the NVMe temp disk at startup (idempotent script)</h2>
<p>The solution that worked for me was to create a <strong>PowerShell script</strong> that runs on startup and does the following:</p>
<ul>
<li>Find the first <strong>non-OS NVMe disk</strong> ( you can edit it to get the drive based on name or a different attribute, as per your current setup)</li>
<li>If it is <strong>RAW</strong>, initialize it (GPT), create one partition, and format it NTFS</li>
<li>Force the drive letter to <strong>T:</strong> (so my tempdb path is stable)</li>
<li>Create the folder <strong>T:\SQLTemp</strong></li>
<li>Grant permissions to the default instance service SID: <strong>NT SERVICE\MSSQLSERVER</strong></li>
</ul>
<p>Here is the script exactly as I used it:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell"># Pick the temp NVMe disk: non-OS, NVMe bus, and possibly RAW
$disk = Get-Disk | Where-Object {
    $_.IsBoot -eq $false -and $_.IsSystem -eq $false -and $_.BusType -eq 'NVMe'
} | Sort-Object Number | Select-Object -First 1

if ($null -eq $disk) { exit 0 }

# If RAW, initialize + partition + format and force drive letter T:
if ($disk.PartitionStyle -eq 'RAW') {
    Initialize-Disk -Number $disk.Number -PartitionStyle GPT -PassThru | Out-Null
    $part = New-Partition -DiskNumber $disk.Number -UseMaximumSize -DriveLetter T
    Format-Volume -Partition $part -FileSystem NTFS -NewFileSystemLabel "TEMP" -AllocationUnitSize 65536 -Confirm:$false | Out-Null
}

# If it’s already formatted but missing letter T, try to assign it
$vol = Get-Volume | Where-Object { $_.FileSystemLabel -eq 'TEMP' } | Select-Object -First 1
if ($vol -and $vol.DriveLetter -ne 'T') {
    Set-Partition -DriveLetter $vol.DriveLetter -NewDriveLetter T
}

# Ensure TempDB folder exists
$tempFolder = "T:\SQLTemp"
if (!(Test-Path $tempFolder)) { New-Item -ItemType Directory -Path $tempFolder | Out-Null }

# Grant SQL Server service account (default instance service SID) rights
icacls $tempFolder /grant "NT SERVICE\MSSQLSERVER:(OI)(CI)F" /T | Out-Null

# Start SQL
Start-Service "MSSQLSERVER"
Start-Service "SQLSERVERAGENT" -ErrorAction SilentlyContinue</pre>
<h2>Important detail: make sure SQL Server doesn’t start before the disk is ready</h2>
<p>Just initializing the disk is not enough if SQL Server starts too early.</p>
<ul>
<li>Set the <strong>SQL Server (MSSQLSERVER)</strong> service startup type from <strong>Automatic</strong> to <strong>Manual</strong></li>
<li>Set the <strong>SQL Server Agent (MSSQLSERVER)</strong> service startup type from <strong>Automatic</strong> to <strong>Manual</strong></li>
</ul>
<p>Then create a new <strong>Windows Task</strong> (use Task Scheduler) to be run at system startup:</p>
<ul>
<li><strong>Trigger:</strong> At startup</li>
<li><strong>Security options:</strong> Run whether the user is logged on or not</li>
<li><strong>Security options:</strong> Run with highest privileges</li>
<li><strong>Action:</strong> <code>powershell.exe</code></li>
<li><strong>Arguments:</strong> <code>-ExecutionPolicy Bypass -File C:\Scripts\Init-TempDisk-AndStartSql.ps1</code></li>
</ul>
<p>After a reboot, the VM brought up the temp drive first, then SQL Server came online cleanly. The deployment succeeded, and tempdb could be placed where it belongs.</p>
<h2>Alternative options (if you don’t want tempdb on local storage)</h2>
<p>If you want a simpler/safer setup (at the cost of I/O), you can avoid placing tempdb on ephemeral storage entirely:</p>
<ul>
<li>Use a VM size where the temp disk is presented consistently and already formatted</li>
<li>Place tempdb on a managed data disk (Premium SSD / Ultra Disk) and configure it that way from the start.</li>
</ul>
<h3>Important note: How SQL IaaS starts SQL Server (and why you should not edit its startup task)</h3>
<p>When you deploy a SQL Server VM from the Azure Marketplace image, Azure installs the <strong>SQL Server IaaS Agent extension</strong>. One of the things this extension does is create a <strong>Windows Scheduled Task</strong> (running at system startup) that executes<code>SqlIaaSExtension.SqlServerStarter.exe</code>. This starter component is responsible for bringing the SQL Server services online in a predictable way (and for some configurations, it also validates or prepares required paths used by SQL Server).</p>
<p>A key detail is that this scheduled task is <strong>managed by the SQL IaaS extension</strong>. That means it is effectively treated as &#8220;desired state&#8221;: on every VM boot, the extension can <strong>recreate or reset</strong> the task to its default definition. Because of that, any manual edits (for example, adding a PowerShell step into the same task) are <strong>not persistent</strong>. If you add your PowerShell action directly into the SQL IaaS startup task, it will typically be <strong>deleted on the next VM startup</strong>, because the extension rewrites the task back to the default version.</p>
<p>The correct approach is to leave the SQL IaaS task untouched and create <strong>a separate startup scheduled task</strong> for your own script (for example, to initialize and format the ephemeral NVMe disk and create <code>T:\SQLTemp</code>). Your task can run at startup and ensure the drive and folder exist, and then (optionally) start or restart the SQL Server service if needed.</p>
<h3>References</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/troubleshoot/sql/azure-sql/sql-deployment-fails-drive-not-ready" target="_blank" rel="noopener">SQL VM fails to deploy or SQL Server instance can’t come online after restart (Drive not ready)</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/sql-server-iaas-agent-extension-automate-management?view=azuresql" target="_blank" rel="noopener">SQL Server IaaS Agent extension overview</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/storage-configuration?view=azuresql" target="_blank" rel="noopener">Configure storage for SQL Server on Azure VMs</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/sql-server-2025-on-azure-vm-failed-to-deploy-system-drive-returned-status-not-ready-for-use-tempdb-on-uninitialized-local-nvme/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server 2025: Web Edition Is Gone</title>
		<link>https://sqlpowered.com/sql-server-2025-web-edition-is-gone/</link>
					<comments>https://sqlpowered.com/sql-server-2025-web-edition-is-gone/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 04 Jan 2026 22:51:43 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5769</guid>

					<description><![CDATA[As a SQL Server DBA, I usually don’t panic about licensing changes — but the removal of SQL Server Web Edition in SQL Server 2025 is one of those changes that immediately hit a real production project I’m responsible for.Web Edition has been the quiet workhorse for years: small web...]]></description>
										<content:encoded><![CDATA[<article class="sp-article">As a SQL Server DBA, I usually don’t panic about licensing changes — but the removal of <strong>SQL Server Web Edition</strong> in <strong>SQL Server 2025</strong> is one of those changes that immediately hit a real production project I’m responsible for.Web Edition has been the quiet workhorse for years: small web applications, low to moderate workloads, predictable costs. Nothing fancy — just a reliable SQL Server engine at a price that made sense.</p>
<p><strong>With SQL Server 2025, that option is gone.</strong></p>
<p>Microsoft has confirmed that <strong>SQL Server 2022</strong> is the last version supporting Web Edition. From 2025 onward, if you want to stay current, <strong>Standard Edition</strong> becomes the default replacement — and that’s where the real problem starts.</p>
<p>In one of my Azure VM–based projects, we were running SQL Server Web Edition on a VM with <strong>12 vCores and 48 GB RAM</strong>. The SQL licensing cost was roughly <strong>70 USD per month</strong>, fully acceptable for the workload and business value.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5770" src="https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing.png" alt="" width="1875" height="1327" srcset="https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing.png 1875w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-300x212.png 300w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-1024x725.png 1024w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-141x100.png 141w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-768x544.png 768w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-1536x1087.png 1536w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2022_Web_Pricing-360x255.png 360w" sizes="auto, (max-width: 1875px) 100vw, 1875px" /></p>
<p>After switching the same VM to <strong>SQL Server Standard Edition</strong>, the SQL license component alone jumped to <strong>~870 USD per month</strong>.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5771" src="https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing.png" alt="" width="2048" height="1308" srcset="https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing.png 2048w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-300x192.png 300w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-1024x654.png 1024w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-150x96.png 150w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-768x491.png 768w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-1536x981.png 1536w, https://sqlpowered.com/wp-content/uploads/2026/01/SQLServer2025_Standard_Pricing-360x230.png 360w" sizes="auto, (max-width: 2048px) 100vw, 2048px" /></p>
<p>Same VM.<br />
Same workload.<br />
Same databases.<br />
<strong>Almost 12× higher SQL cost.</strong></p>
<h2>What changed — in practice</h2>
<ul>
<li><strong>SQL Server Web Edition is discontinued in 2025</strong></li>
<li>SQL Server 2022 Web Edition remains supported, but only as a temporary safe harbor until 2033</li>
<li><strong>Standard Edition becomes the lowest “future-proof” option</strong></li>
<li>Licensing is <strong>per-core</strong>, and costs scale aggressively with CPU count</li>
<li>Even modest VMs suddenly become expensive SQL hosts</li>
</ul>
<h2>My takeaway</h2>
<p>SQL Server Web Edition disappearing is not just a line in the release notes — it’s a <strong>budget-changing event</strong>.</p>
<p>If you’re running Web Edition today, my advice is simple: <strong>audit your environments now</strong> and calculate what Standard Edition will really cost you — before SQL Server 2025 forces the conversation.</p>
<p>Sometimes the most expensive SQL feature is not a feature at all — it’s the edition.</p>
</article>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/sql-server-2025-web-edition-is-gone/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Managing String Content in View Definitions</title>
		<link>https://sqlpowered.com/store-any-kind-of-a-string-in-your-view-definition/</link>
					<comments>https://sqlpowered.com/store-any-kind-of-a-string-in-your-view-definition/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 26 Jun 2024 06:01:43 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5510</guid>

					<description><![CDATA[The hidden text (this_is_hidden_text_in_the_view) in the view definition is an intriguing addition. Anything after the SELECT * FROM sys.tables query that is not a valid SQL statement (like a comment or plain text) will not be executed or parsed by SQL Server. It essentially becomes invisible to the engine and...]]></description>
										<content:encoded><![CDATA[<p>The hidden text (<code>this_is_hidden_text_in_the_view</code>) in the view definition is an intriguing addition. Anything after the <code>SELECT * FROM sys.tables</code> query that is not a valid SQL statement (like a comment or plain text) will not be executed or parsed by SQL Server. It essentially becomes invisible to the engine and is purely for informational or decorative purposes within the script.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-highlight="5">CREATE OR ALTER VIEW dbo.SampleView
AS
	SELECT	* FROM sys.tables

	this_is_hidden_text_in_the_view

GO</pre>
<p>In the medata you will see:</p>
<p><code class="EnlighterJSRAW" data-enlighter-language="sql">SELECT * FROM sys.[sql_modules] WHERE [definition] LIKE '%hidden_tex%'</code></p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5711" src="https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view.png" alt="" width="592" height="28" srcset="https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view.png 1596w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-300x14.png 300w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-1024x48.png 1024w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-150x7.png 150w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-768x36.png 768w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-1536x72.png 1536w, https://sqlpowered.com/wp-content/uploads/2024/06/text-hidden-in-view-360x17.png 360w" sizes="auto, (max-width: 592px) 100vw, 592px" /></p>
<p>Storing free text that isn&#8217;t a valid T-SQL statement within a view definition can indeed break code consistency rules and potentially lead to confusions in database management and development. Here are several key points to explain this concern:</p>
<ol>
<li><strong>Code Consistency</strong>: Views in SQL Server are designed to encapsulate logical queries that retrieve and present data in a structured manner. They should adhere to standard SQL syntax and maintain a clear purpose. Introducing free text that isn&#8217;t part of a valid SQL statement contradicts this principle of consistency. It blurs the line between executable code and documentation, potentially making it harder for developers to understand and maintain the view over time.</li>
<li><strong>Parsing and Execution</strong>: SQL Server parses and executes the view definition to retrieve data when the view is queried. Any non-SQL text included in the view definition, such as comments or free text, is ignored during this process. While this doesn&#8217;t affect the functionality of the view directly, it can mislead developers who might expect the free text to behave as part of the SQL logic.</li>
<li><strong>Maintenance Challenges</strong>: Over time, as views are updated or modified, the non-SQL text within their definitions may become outdated or irrelevant. This can confuse developers who rely on accurate documentation embedded within the code. It also creates maintenance challenges, as developers might overlook or misinterpret the purpose of the non-SQL text during updates.</li>
<li><strong>Communication and Collaboration</strong>: In collaborative environments, adhering to consistent coding practices ensures that all team members can easily understand and work with database objects. Non-standard practices like embedding free text in view definitions can hinder effective communication about the view&#8217;s purpose, leading to misunderstandings or errors in development and maintenance tasks.</li>
<li><strong>Documentation Separation</strong>: Best practices advocate for separating documentation from executable code. While comments within SQL code (using <code>/* */</code> or <code>--</code>) are valid and beneficial for documenting SQL logic, embedding free text directly within view definitions blurs this distinction. It introduces content that isn&#8217;t intended for execution but might be mistakenly interpreted as such.</li>
<li><strong>Risk of Misinterpretation</strong>: Developers unfamiliar with the database might misinterpret non-SQL text within view definitions as part of the SQL logic. This misunderstanding can lead to incorrect assumptions about the functionality or design intent of the view, potentially causing errors or inefficiencies in application development.</li>
</ol>
<h3>Conclusion</h3>
<p>In conclusion, while adding non-SQL free text to view definitions might seem convenient for documentation purposes, it poses risks to code consistency and clarity in SQL Server development. It&#8217;s advisable to adhere to established coding standards and separate documentation from executable code to maintain transparency, facilitate maintenance, and mitigate confusion among developers working with database objects. Clear communication and consistent practices are key to ensuring the reliability and manageability of database systems over time.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/store-any-kind-of-a-string-in-your-view-definition/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SET STATISTICS PROFILE</title>
		<link>https://sqlpowered.com/set-statistics-profile/</link>
					<comments>https://sqlpowered.com/set-statistics-profile/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Mon, 17 Jun 2024 19:02:27 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5702</guid>

					<description><![CDATA[SQL Server provides various tools and commands to help database administrators and developers analyze and optimize query performance. One of these commands is SET STATISTICS PROFILE. This command is particularly useful for obtaining a detailed execution plan along with the runtime statistics of a query, which can be invaluable for...]]></description>
										<content:encoded><![CDATA[<p>SQL Server provides various tools and commands to help database administrators and developers analyze and optimize query performance. One of these commands is <code>SET STATISTICS PROFILE</code>. This command is particularly useful for obtaining a detailed execution plan along with the runtime statistics of a query, which can be invaluable for performance tuning.</p>
<p><code>SET STATISTICS PROFILE</code> , when enabled, returns detailed information about the execution of a query. This includes the execution plan and the number of rows affected by each operation. The command is helpful for understanding how SQL Server executes a query and where potential bottlenecks might be.</p>
<p>When <code>SET STATISTICS PROFILE</code> is ON, SQL Server returns two result sets. The first is the regular result of the query, and the second is a detailed report showing the actual execution plan with runtime statistics.</p>
<h2>Syntax</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SET STATISTICS PROFILE { ON | OFF }</pre>
<h2>How to Use SET STATISTICS PROFILE</h2>
<p>To use <code>SET STATISTICS PROFILE</code>, you simply turn it ON before running your query and then turn it OFF afterward. Below is a step-by-step guide with a practical example.</p>
<h2>Practical Example</h2>
<p>Consider a scenario where you have a database with the following table:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    Department NVARCHAR(50),
    Salary DECIMAL(10, 2)
);</pre>
<p>Let&#8217;s populate this table with some sample data:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">INSERT INTO Employees (EmployeeID, FirstName, LastName, Department, Salary) VALUES
(1, 'John', 'Doe', 'Engineering', 60000),
(2, 'Jane', 'Smith', 'Marketing', 50000),
(3, 'Sam', 'Brown', 'Engineering', 75000),
(4, 'Sue', 'Johnson', 'HR', 45000);</pre>
<p>Now, suppose you want to analyze the performance of a query that retrieves all employees from the Engineering department:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SET STATISTICS PROFILE ON;

SELECT * FROM Employees WHERE Department = 'Engineering';

SET STATISTICS PROFILE OFF;</pre>
<h2>Understanding the Output</h2>
<p>When you run the above commands, SQL Server will return the query results as usual. Additionally, it will provide a second result set with the execution plan and statistics. Here’s an example of what the output might look like:</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5706" src="https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2.png" alt="" width="1351" height="60" srcset="https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2.png 3369w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-300x13.png 300w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-1024x45.png 1024w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-150x7.png 150w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-768x34.png 768w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-1536x68.png 1536w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-2048x91.png 2048w, https://sqlpowered.com/wp-content/uploads/2024/06/SET_PROFILE_2-360x16.png 360w" sizes="auto, (max-width: 1351px) 100vw, 1351px" /></p>
<h2>Key Columns in the Output</h2>
<ul>
<li><strong>StmtText:</strong> The text of the SQL statement being executed.</li>
<li><strong>NodeId:</strong> The identifier for the operation node within the execution plan.</li>
<li><strong>PhysicalOp:</strong> The physical operation performed (e.g., Index Scan, Table Scan).</li>
<li><strong>LogicalOp:</strong> The logical operation performed (e.g., Filter, Join).</li>
<li><strong>EstimateRows:</strong> The estimated number of rows that will be processed.</li>
<li><strong>EstimateIO:</strong> The estimated I/O cost.</li>
<li><strong>EstimateCPU:</strong> The estimated CPU cost.</li>
<li><strong>TotalSubtreeCost:</strong> The estimated total cost of the query.</li>
<li><strong>OutputList:</strong> The list of columns output by this operation.</li>
</ul>
<h2>Benefits of Using SET STATISTICS PROFILE</h2>
<ul>
<li><strong>Detailed Insights:</strong> Provides detailed execution plans with actual runtime statistics.</li>
<li><strong>Performance Tuning:</strong> Helps identify bottlenecks and inefficient operations in queries.</li>
<li><strong>Optimization:</strong> Assists in optimizing queries by giving visibility into the execution process.</li>
</ul>
<h2>Conclusion</h2>
<p><code>SET STATISTICS PROFILE</code> is a powerful tool in SQL Server for anyone looking to optimize their queries and improve performance. By providing detailed execution plans and runtime statistics, it allows developers and DBAs to gain a deeper understanding of how their queries are executed and where they can make improvements. Utilizing this command effectively can lead to significant performance gains and more efficient database operations.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/set-statistics-profile/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
