The Dangerous Truth About Scalar Functions in 45 Seconds, The "45 Seconds DBA Series" | Part 20

Before we dive into today's topic, if you missed my previous post you can take a look at SSMS 22.6.0 Is OUT! Review & Test!. 👉 If you found this deep-dive helpful, feel free to check out the ads—your support helps me keep creating high-quality SQL Server content for the community.

The Dangerous Truth About Scalar Functions in 45 Seconds

The "45 Seconds DBA Series" | Part 20


Scalar UDFs are the silent killers of SQL Server performance. In this post, I will reveal why they hide their true cost and how they turn a fast query into a row-by-row disaster.

🧠 TL;DR
  • ✔️ Scalar UDFs force RBAR (Row-By-Agonizing-Row) execution, bypassing the set-based power of the optimizer. 💣
  • ✔️ Inhibits Parallelism: Traditional scalar functions force your entire query to run on a single thread. 🧵
  • ✔️ Hidden Costs: Execution plans often show UDF cost as 0%, masking the massive CPU overhead. 🔍
  • ✔️ The Fix: Use Inline Table-Valued Functions (iTVFs) or SQL 2019+ Scalar Inlining. 🚀

Hi SQL SERVER Guys and Gals,

We all love clean code, and wrapping logic into a reusable Scalar User-Defined Function (UDF) feels like good software engineering. However, in the database world, this "clean code" is often a performance nightmare. Every time you use a scalar function in a SELECT or WHERE clause, you are essentially telling SQL Server to abandon its high-speed engine and work like a 1990s spreadsheet. Let’s break down the mechanics.

🔍 DIAGNOSIS: The "Black Box" Problem

SQL Server treats Scalar UDFs as a Black Box. When the query optimizer generates a plan, it doesn't "look inside" the function. This leads to two critical failures:

  • Iterative Execution: If your table has 1 million rows, the function is called 1 million times. This context switching between the engine and the UDF context destroys throughput.
  • 🧵 Serial Plans: Before SQL Server 2019, a query containing a scalar UDF was forced into a serial execution plan. No parallelism, no matter how many cores you have.

Refer to the Official Microsoft Documentation on UDF Inlining for a deeper look at the internal mechanics.

🧪 QUERY: Scalar vs. Inline

Compare the performance impact yourself. Notice the difference in "CPU Time" in your execution statistics.

-- 🔍 The Dangerous Scalar Approach
CREATE FUNCTION dbo.fn_GetDiscount (@Price MONEY)
RETURNS MONEY
AS
BEGIN
    RETURN (@Price * 0.10);
END;
GO

-- This will run row-by-row!
SELECT OrderID, dbo.fn_GetDiscount(TotalDue) 
FROM Sales.SalesOrderHeader;
-- 🧪 The Performance-First Inline Approach
CREATE FUNCTION dbo.itvf_GetDiscount (@Price MONEY)
RETURNS TABLE
AS
RETURN (
    SELECT @Price * 0.10 AS Discount
);
GO

-- This allows the optimizer to merge logic into the main query
SELECT S.OrderID, D.Discount
FROM Sales.SalesOrderHeader S
CROSS APPLY dbo.itvf_GetDiscount(S.TotalDue) D;

🚀 FIX: Modern Strategies

If you are on SQL Server 2019 (15.x) or later, many scalar functions are now "Inlined" automatically. However, there are many requirements (no WHILE loops, no GETDATE(), etc.) that can disable this feature.

The Expert Rule: If your function can be written as a single RETURN SELECT, always use an Inline Table-Valued Function (iTVF). It forces the optimizer to treat the logic as part of the execution plan, enabling parallelism and accurate cost estimation.

🚀 My REAL Strategy

In 25 years of tuning, I’ve seen UDFs turn sub-second queries into 10-minute waits. My Real Strategy: Check sys.dm_exec_function_stats. This DMV tracks the execution time of your functions. If you see a function with millions of executions and a high total_worker_time, that’s your bottleneck. Don't trust the execution plan's percentage—it lies when it comes to UDFs.

📊 TAKEAWAY

  • Context Switching: Scalar UDFs overhead is often greater than the logic they contain.
  • 💣 Parallelism Killer: One scalar UDF can lock your query to a single CPU core.
  • 🚀 Refactor: Convert Scalar UDFs to Inline TVFs for an immediate performance boost.

📢 Support the Blog: Did you find this deep-dive helpful? The ads you see here are selected to reflect your interests. If a partner's offer catches your eye, give it a look! Your engagement helps me continue publishing premium SQL Server content for the community.

Biondi Luca @2026 - Sharing over 25 years of Gained Knowledge for Passion. Share if you like my posts!

🧠 Master SQL Server Performance Hub

Expand your knowledge with my latest deep-dives and performance guides.

Don't forget to check my April 2026 Recap for a complete monthly summary.

Comments

I Post più popolari

Speaking to Sql Server, sniffing the TDS protocol

SQL Server, find text in a Trigger, Stored Procedures, View and Function. Two ways and what ways is better

SQL Server, Avoid that damn Table Spool!