大数跨境
0
0

使用绑定参数让 SQL 查询更快

使用绑定参数让 SQL 查询更快 小何出海
2025-10-26
8
导读:当然,你可能已经使用过绑定参数了,但你是否知道它是一种性能优化技巧呢?

当然,你可能已经使用过绑定参数了,但你是否知道它是一种性能优化技巧呢?

你可能听说过类似的说法:“使用绑定参数(参数化查询)而不是拼接 SQL 字符串可以提升 SQL 性能。”

接下来,你将了解其中的原因。

什么是绑定参数?

绑定参数是 SQL 语句中的一个占位符,是一个变量,其值在执行时提供。

占位符可以是:

  • ?
  • @variable
  • :variable

因此,与其在查询中硬编码字面值,不如“绑定”一个参数:

SELECT
    *
FROM [db_sales_test].[dbo].[fact_sales]
WHERE [product_id] = 60;

EXEC sp_executesql
    N'SELECT * FROM fact_sales WHERE product_id = @product_id',
    N'
@product_id INT',
    @product_id = 60;

这两条查询会返回相同的数据,但 SQL Server 在内部对它们的处理方式完全不同。

不使用参数会发生什么?

当你运行以下查询时:

SELECT
    *
FROM [db_sales_test].[dbo].[fact_sales]
WHERE [product_id] = 60;

SQL Server 必须执行以下操作:

  1. 解析 SQL 字符串。
  2. 验证元数据(表、列、索引)。
  3. 运行优化器以选择最佳计划。
  4. 缓存该执行计划。

如果你稍后运行以下查询:

SELECT
    *
FROM [db_sales_test].[dbo].[fact_sales]
WHERE [product_id] = 147;

SQL Server 会将这条查询视为全新的查询,因为只是值不同。因此,它会编译并缓存第二个执行计划,尽管查询的其余部分完全相同。

听起来很疯狂,对吧?想象一下这发生在事务型数据库中……

突然间,你的计划缓存中充满了几乎相同的查询,浪费了 CPU 和内存。

绑定参数登场

如果我们对查询进行参数化:

EXEC sp_executesql
    N'SELECT * FROM fact_sales WHERE product_id = @product_id',
    N'
@product_id INT',
    @product_id = 60;
  • 查询文本将始终保持不变。
  • 只有参数值会改变。
  • SQL Server 将重用相同的执行计划(我们稍后会讨论这一点)。

这意味着你将减少编译开销,计划缓存也会更小,从而实现快速查询。

实际操作

让我们通过一个示例来验证这一点,好吗?

首先运行以下两条查询:

SELECT
    *
FROM [db_sales_test].[dbo].[fact_sales]
WHERE [product_id] = 147;

SELECT
    *
FROM [db_sales_test].[dbo].[fact_sales]
WHERE [product_id] = 60;

然后,我们可以检查缓存的计划:

SELECT
    cp.usecounts,
    cp.objtype,
    st.text
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
WHERE st.text LIKE '%fact_sales%';

在结果中,我们可以看到两个独立的缓存计划:

缓存计划

现在,如果我们运行一条参数化的查询,使用 sp_executesql

EXEC sp_executesql
    N'SELECT * FROM fact_sales WHERE product_id = @product_id',
    N'
@product_id INT',
    @product_id = 58;
参数化查询的缓存计划

我们可以看到只有一个计划,随着查询的重复使用,usecounts 会增加。

不错吧! :)

重要提示:另一个好处是绑定参数可以防止 SQL 注入,因此在应用程序中使用它是一种很好的实践。

但是……参数嗅探怎么办?

是的,世界并非尽善尽美。我们在使用绑定参数时还需要考虑一些问题……

有一个问题是:参数化可能会导致 参数嗅探问题

例如:

  • 假设 [product_id] = 1 只返回 3 行,但 [product_id] = 500 返回 100 万行

如果 SQL Server 使用 [product_id] = 1 来编译计划,它可能会选择嵌套循环连接(适用于小数据集)。

但当它尝试运行 [product_id] = 500 时,相同的计划可能会表现得很糟糕。

这就是 参数嗅探,SQL Server 会使用第一个参数来构建计划,而这个计划在后续执行中可能表现不佳。

一个解决方案是使用 OPTION (RECOMPILE)

EXEC sp_executesql
    N'SELECT * FROM fact_sales WHERE product_id = @product_id OPTION (RECOMPILE);',
    N'@product_id INT',
    @product_id = 2;

SQL 将创建另一个缓存执行计划:

使用 OPTION (RECOMPILE) 的缓存计划

使用绑定参数不仅仅是写出“更干净”的 SQL。

它关乎:

  • 执行计划重用 → 更快的查询。
  • 减少浪费的 CPU → 更高的吞吐量。
  • 更小的计划缓存 → 更少的内存压力。
  • 更安全的查询 → 防止 SQL 注入。

参数化是你能够实现的最简单且最有效的性能优化之一。


【声明】内容源于网络
0
0
小何出海
跨境分享阁 | 长期积累行业知识
内容 41133
粉丝 1
小何出海 跨境分享阁 | 长期积累行业知识
总阅读227.2k
粉丝1
内容41.1k