如何为 openGauss 调优带有 CASE 表达式的 SQL 语句 ?

openGauss 是一个开源的关系型数据库管理系统(RDBMS),起源于 PostgreSQL。它专为高性能、高可用性和企业级功能而设计。openGauss 最初由华为开发,后来开源给社区。

以下是开发人员可能会遇到的一个常见问题:编写动态 SQL 语句时,在 CASE 表达式中硬编码了 a = ‘low’,而不是使用绑定变量 = :var,如下所示:

SELECT *
FROM   employee
WHERE 
       CASE
         WHEN emp_salary< 1000
         THEN ‘low’
         WHEN emp_salary>100000
         THEN ‘high’
         ELSE ‘Normal’
       END = ‘low’

以下是该 SQL 语句的查询计划,其执行时间为 2.20 秒。由于 CASE 表达式无法利用 emp_salary 索引,查询对 EMPLOYEE 表执行了顺序扫描(Seq Scan)。

我们可以使用以下带有多个 OR 条件的语法来重写 CASE 表达式。

select *
  from employee
 where (emp_salary < 1000 and
        ‘low’ = ‘low’ or
        (not (emp_salary < 1000)) and
        emp_salary > 100000 and
        ‘high’ = ‘low’ or
        (not (emp_salary < 1000 or
              emp_salary > 100000)) and
        ‘Normal’ = ‘low’);

如果 emp_salary 字段可为空(nullable),SQL 查询应按照以下方式编写:

select *
  from employee
 where (emp_salary < 1000 and
        ‘low’ = ‘low’ or
        ((not (emp_salary < 1000)) or
         emp_salary is null) and
        emp_salary > 100000 and
        ‘high’ = ‘low’ or
        ((not (emp_salary < 1000 or
               emp_salary > 100000)) or
         emp_salary is null) and
        ‘Normal’ = ‘low’)

以下是重写后的 SQL 查询计划,其执行时间为 0.002 秒,比原始语法快了 1100 倍。新的查询计划使用了针对 emp_salary 索引的位图索引扫描(Bitmap Index Scan)。
这种重写可以通过 Tosska SQL Tuning Expert Pro 工具为 openGauss 自动实现。还有一些其他重写方法可以提供更好的性能,但由于篇幅限制,本文不适合详细讨论。我可能会在未来的博客文章中进一步探讨这些方法。

Tosska SQL Tuning Expert Pro (TSEG Pro™) for OpenGauss® – Tosska Technologies Limited

如何为 openGauss 调优带有“EXISTS 子查询”的 SQL ?

openGauss 是一种开源的关系型数据库管理系统(RDBMS),它起源于 PostgreSQL。openGauss 旨在提供高性能、高可用性和企业级功能。最初由华为开发,后来被开源给社区。

在大多数数据库的 SQL 优化器中,一个常见问题是对 EXISTS 子查询 的低效处理。以下是一个带有 EXISTS 子查询的 SQL 语句示例。该查询从 emp_subsidiary 表中检索与 employee 表中的 salary、grade_id 和 department_id 匹配的记录。

select *
  from emp_subsidiary a
 where exists (select ‘x’
                 from employee b
                where a.emp_salary = b.emp_salary and
                      b.emp_grade = a.emp_grade and
                      a.emp_dept = b.emp_dept)

以下是查询计划;完成该查询需要 10.35 秒。

查询计划显示了一个 Hash Inner Join,其中包含对 emp_subsidiary 表的顺序扫描(sequential scan)和对 employee 表的顺序扫描。该查询计划的性能看起来是合理的,如果不引入新的索引,性能将无法进一步提升。

有人可能会建议将 SQL 重写为使用 IN 语句,以查看查询是否可以改进,如下所示:

select *
  from emp_subsidiary a
 where (a.emp_salary, a.emp_grade, a.emp_dept) in (select b.emp_salary,
                                                          b.emp_grade,
                                                          b.emp_dept
                                                     from employee b)

重写后的 SQL 并未生成新的查询计划,且未观察到性能提升。为了解决这个问题,让我进一步将原始 SQL 语句重写为带有 INTERSECT 语句的子查询。

显然,重写后的 SQL 在子查询中引入了一个额外的操作,即 employee 表与 emp_subsidiary 表进行交集运算。这意味着只有 employee 表和 emp_subsidiary 表之间基于 emp_salary、emp_grade 和 emp_dept 的交集记录会被返回。因此,子查询的结果集大幅减少,从而显著降低了高成本的 Hash Aggregate 操作。

select *
  from emp_subsidiary a
 where (a.emp_salary, a.emp_grade, a.emp_dept) in (select b.emp_salary,
                                                          b.emp_grade,
                                                          b.emp_dept
                                                     from employee b
                                                   intersect
                                                   select a.emp_salary,
                                                          a.emp_grade,
                                                          a.emp_dept
                                                     from emp_subsidiary a)

重写后的 SQL 需要 4 秒 完成,其查询计划如下。与原始查询计划相比,新计划略显复杂。然而,Hashed Aggregate 操作的成本显著低于原始 SQL,实际执行时间也反映了这一改进。

这种语法重写方法只有在 INTERSECT 操作引入的开销被其显著减少的子查询结果集所抵消时才有用。

重写后的 SQL 比原始 SQL 快 2 倍以上。这种优化也可以通过使用 Tosska SQL Tuning Expert 在 openGauss 中实现。

Tosska SQL Tuning Expert Pro (TSEG Pro™) for openGauss® – 珠海图思科软件有限公司

如何为 openGauss 调优带有“IN 子查询”的 SQL ?

openGauss 是一种开源的关系型数据库管理系统(RDBMS),它起源于 PostgreSQL。openGauss 旨在提供高性能、高可用性和企业级功能。最初由华为开发,后来被开源给社区。openGauss 的 SQL 优化器基于 PostgreSQL,但经过了显著的增强和修改,以提升性能、可扩展性并支持企业级工作负载。虽然官方文档中没有明确说明 openGauss 是从哪个 PostgreSQL 版本继承的初始代码库,但普遍认为 openGauss 起源于 PostgreSQL 9.2.4。因此,当前版本的 openGauss 中可能仍然存在一些来自旧版 PostgreSQL 的遗留 SQL 优化器问题。

在不成熟的 SQL 优化器中,一个常见问题是对 IN 子查询的低效处理。以下是一个带有 IN 子查询的 SQL 语句示例。该查询从 employee 表中检索与 emp_subsidiary 表中 salary 匹配的记录,条件是两者的 emp_id 相同。

select *
  from employee a
 where a.emp_salary in (select b.emp_salary
                          from emp_subsidiary b
                         where a.emp_id = b.emp_id)

以下是查询计划;完成该查询需要 7.2 秒。

查询计划显示了对 employee 表的顺序扫描(sequence scan)和对 emp_subsidiary 表的索引扫描(index scan)。然而,这种查询不适合 employee 与 emp_subsidiary 比例为 30:1 的场景。如果 openGauss 拥有更强大的 SQL 优化器,它应该包含一个内部的 SQL 语法重写机制,将 IN 语句转换为 JOIN 或 EXISTS 语句,从而允许探索更高效的查询计划。>br>

下面,我将使用 EXISTS 语句重写 SQL,如下所示:

select *
  from employee a
 where exists (select ‘x’
                 from emp_subsidiary b
                where a.emp_salary = b.emp_salary and
                      a.emp_id = b.emp_id)


重写后的 SQL 仅需 0.34 秒 即可完成,并且在查询计划中使用了 Merge Semi Join——这是一种无法通过原始 IN 语法生成的计划。我们可以看到,重写后的 SQL 成本显著低于原始 SQL 语句。这表明,在 openGauss 对原始查询进行 SQL 优化时,Merge Semi Join 计划并未在其探索的计划空间内。

重写后的 SQL 比原始 SQL 快 20 倍以上。这种优化也可以通过使用 Tosska SQL Tuning Expert 在 openGauss 中实现。

Tosska SQL Tuning Expert Pro (TSEG Pro™) for openGauss® – 珠海图思科软件有限公司

如何使用查询重写插件在 MySQL 数据库中调整 SQL II?

MySQL 中的查询重写插件是一个组件,允许您在执行之前修改传入的 SQL 查询。它提供了根据特定需求转换、路由、过滤或扩展查询的功能。

如果您已安装了该插件,可以使用以下 SQL 语句来定义您的 SQL 替换规则和错误消息处理.

INSERT INTO query_rewrite.rewrite_rules (message, pattern, replacement)
VALUES(Unique_ID, Original_SQL, Rewrite_SQL);

MySQL 中的 query_rewrite.rewrite_rules 表存储了 Query Rewriter 插件用于重写 SQL 查询的规则。该表包含两列:

Pattern – 此列代表触发 SQL 查询重写的模式或条件。它定义了要匹配的特定查询或查询模式。

Replacement – 此列指定应该应用于匹配的查询或查询模式的替换或转换。

当执行 SQL 查询时,Query Rewriter 插件会检查 query_rewrite.rewrite_rules 表以查找匹配的模式。如果模式与执行的查询匹配,插件将使用相应的替换重写查询。这使您能够根据特定的模式或条件修改查询结构、优化查询或添加自定义逻辑。
以下是一个包含硬编码字面量的 SQL 语句示例,执行该 SQL 需要 2.1 秒,并附有以下查询计划。

SELECT   *
FROM     employee
WHERE    emp_id in (SELECT emp_id id
                    FROM   emp_subsidiary
                    where  emp_dept < ‘D’)
ORDER BY emp_id LIMIT 1;

以下屏幕显示了通过 Tosska DB Ace SQL 调优工具识别出的性能显著提升的替代 SQL 语句。由于注入 JOIN ORDER 提示,此优化后的 SQL 查询比原始 SQL 快了300多倍.

现在,我们需要将这个优化后的 SQL 与原始 SQL 一起部署到数据库中。然而,一个挑战出现在条件“emp_dept < 'D'”上,当使用一个带有不同硬编码字面量的 SQL 语句,比如“emp_dept < 'E'”时,它与 SQL 文本不匹配。因此,我们必须使用数值占位符Placeholder来替换硬编码字面量,将其替换为占位符“?”,如下所示。

INSERT INTO query_rewrite.rewrite_rules (message, pattern, replacement)
VALUES(Unique_ID, Original_SQL, Rewrite_SQL);

Original_SQL

SELECT   *
FROM     employee
WHERE    emp_id in (SELECT emp_id id
                    FROM   emp_subsidiary
                    where  emp_dept < ?)
ORDER BY emp_id LIMIT 1

Rewrite_SQL

select   /*+ QB_NAME(QB1) JOIN_ORDER(`employee`@QB1, `emp_subsidiary`@QB2) */ *
from     employee
where    emp_id in (select /*+ QB_NAME(QB2) */ emp_id id
                    from   emp_subsidiary
                    where  emp_dept < ?)
order by emp_id limit 1

Tosska DB Ace for MySQL通过自动化发现优化SQL替代方案和部署具有数值占位符替换的SQL,简化了这一过程。

查询重写插件功能强大且易于使用。最具挑战性的方面是为性能较差的SQL语句找到替代SQL。Tosska DB Ace Enterprise for MySQL可以帮助您自动化这一过程,从识别性能较差的SQL语句到重写SQL语法并部署替代规则。

Tosska DB Ace Enterprise for MySQL – Tosska Technologies Limited

DBAM Tune Rewriter demo – YouTube

如何使用MySQL数据库中的Query Rewriter插件来调优SQL?

MySQL中的Query Rewriter插件是一个组件,允许您在执行SQL之前修改传入的SQL查询。它提供了根据特定需求转换、路由、过滤或扩展查询的能力。该插件在SQL层操作,并可用于优化查询性能、强制执行安全策略、实施数据分区策略或向查询添加附加业务逻辑。通过Query Rewriter插件,您可以自定义和塑造SQL查询,以满足特定需求,在MySQL服务器内灵活控制查询执行。

Query Rewriter查询转换功能使您能够将原始查询重写或转换为等效或更高效的形式。这对于优化性能、简化复杂查询或强制使用特定查询计划非常有用。

在使用此功能之前,您必须安装Query Rewriter插件。Query Rewriter的概念很简单,它是一组预定义的SQL语句,用于替换从应用程序程序触发的特定SQL语句模式。

如果您已安装了该插件,以下SQL语句可用于定义您的SQL替换规则和错误消息处理。

INSERT INTO query_rewrite.rewrite_rules (message, pattern, replacement)
VALUES(Unique_ID, Original_SQL, Rewrite_SQL);

在MySQL中,query_rewrite.rewrite_rules表存储了Query Rewriter插件用于重写SQL查询的规则。该表具有两列:
Pattern – 此列表示触发SQL查询重写的模式或条件。它定义了要匹配的特定查询或查询模式。

Replacement – 此列指定应应用于匹配的查询或查询模式的替换或转换。

当执行SQL查询时,Query Rewriter插件会检查query_rewrite.rewrite_rules表以查找匹配的模式。如果某个模式与执行的查询匹配,插件将使用相应的替换来重写查询。这使您能够根据特定的模式或条件修改查询结构、优化查询或添加自定义逻辑。
我利用message列来定义SQL替换规则的临时唯一标识,这样可以使用以下SQL提取实际的规则ID。

SELECT id into :SID FROM query_rewrite.rewrite_rules where message= Unique_ID;

当您对query_rewrite.rewrite_rules表中的查询重写规则进行更改时,这些更改不会立即生效。相反,MySQL会将规则缓存在内存中以提高性能。然而,如果您希望确保更新后的规则立即生效,可以调用query_rewrite.flush_rewrite_rules()函数。

CALL query_rewrite.flush_rewrite_rules();

如果发生加载错误,插件还会将Rewriter_reload_error状态变量设置为ON,并将错误消息存储在Message列中。

SELECT message FROM query_rewrite.rewrite_rules where id=:SID;

实际上,Query Rewriter插件功能强大且易于使用。最具挑战性的方面是为性能不佳的SQL语句找到替代的SQL语句。Tosska DB Ace Enterprise for MySQL可以帮助您自动化这个过程,从识别性能不佳的SQL语句到重写SQL语法和部署替代规则。

Tosska DB Ace Enterprise for MySQL – Tosska Technologies Limited

DBAM Tune Rewriter demo – YouTube

如何使用计划指南调优 SQL Server 中的临时 SQL?

在 MS SQL Server 中使用计划指南来调优第三方应用程序的 SQL 可以是一种有用的技术,当您需要优化应用程序生成的特定查询或查询集的性能,而无需更改应用程序源代码时。
以下是在 MS SQL Server 中使用计划指南来调优第三方应用程序的 SQL 的步骤,而无需更改源代码:

  • 鉴定导致应用程序性能问题的查询或查询集。您可以使用 SQL Server Profiler 或扩展事件来捕获和分析应用程序生成的 SQL 语句。
  • 创建计划指南,为已鉴定的查询或查询集提供优化的执行计划。这可以涉及修改查询文本或提供查询提示以影响优化器的决策。
  • 测试计划指南,确保它提供了期望的性能改进,并且不会引起任何意外的副作用。
  • 将计划指南部署到生产环境,并监控应用程序的性能,确保计划指南被使用,并且提供了期望的性能改进。

在优化应用程序源代码中的临时 SQL 语句之前,了解 SQL 语句如何与计划指南中指定的语句匹配是至关重要的,包括空格和注释。此外,还需要匹配 SQL 语句的来源。

以下是用于创建计划指南的系统存储过程:

今天的重点将放在使用计划指南来调优临时 SQL (@type = N’SQL’) 上。SQL 有两种类型:独立的 SQL (@module_or_batch = NULL) 和批处理文本中的 SQL (@module_or_batch = N’batch_text’)。例如,如果一个应用程序发送了以下 SQL,并且它独立执行而没有其他代码,那么它属于独立的 SQL。
select top 10 * from employee;
下面的示例展示了一个批处理文本,其中包含了上述列出的 SQL 语句之一,需要通过计划指南进行优化。这个 SQL 语句位于批处理文本的中间。由于相同的 SQL 语句可能来自批处理文本,我们必须通过使用变量 @module_or_batch = N’batch_text’ 来指定具体的批处理文本。因此,必须为同一个 SQL 语句创建两个计划指南,一个用于临时 SQL,一个用于批处理文本。为了准确地确定临时 SQL 的来源,建议使用 SQL Profiler 来捕获需要通过计划指南进行优化的 SQL 语句。

select count(*) from employee;
select top 10 * from  employee;
where emp_id in (select emp_id id
                             from emp_subsidiary
                             where emp_dept<‘h’)

order by emp_name;

Microsoft SQL Server Management Studio提供了一个有用的工具,可以帮助用户创建计划指南,而无需手动执行系统存储过程。然而,了解被优化的SQL语句的类型以及需要输入的相应参数的含义是至关重要的。

尽管对于初学者来说,创建计划指南的步骤可能看起来很复杂,但它们对于在不修改源代码或没有修改权限的情况下改善SQL性能是值得的。然而,最具挑战性和耗时的方面是找到SQL语句的最佳查询提示(@hints = N’OPTION(query_hint [ ,…n ]))。除非您对SQL调优技术有深入的了解并且有足够的时间进行实验,否则您可能需要一个能够从捕获SQL、识别SQL来源类型、自动调优查询提示并便于部署计划指南的产品来简化这个过程。

Tosska DB Ace Enterprise for SQL Server – Tosska Technologies Limited
DBAS Tune SQL PG Standalone – YouTube
DBAS Tune SQL PG Batch – YouTube

如何使用80/20法则来调优数据库应用程序 II ?

之前的文章“如何使用80/20法则来调优数据库应用程序 I”演示了如何应用80/20法则来评估数据库中SQL工作负载的整体性能。在本例中,展示了从Oracle SGA检索到的一组90个SQL语句的图表,每个语句按照其资源使用情况以降序排列列出,最具资源密集型的SQL在左侧。分析显示,大约14.44%的SQL语句占用了80%的总经过时间,而21.11%的SQL语句占用了80%的总CPU时间,表明SQL工作负载分布符合80/20法则。因此,调整SQL可能并不必要,因为这不太可能带来显著的性能改进。

然而,为了更加成本有效地进一步优化数据库性能,建议对高工作量SQL语句的前20%进行深入调查。这将揭示资源利用在前几个SQL语句中急剧下降,使它们成为优化的最关键候选项。


让我们将目标的总资源消耗比例从80%降低到60%,并检查负责利用这些资源的SQL语句。结果很有趣,显示出3个SQL语句占用了60%的经过时间,6个SQL语句占用了60%的CPU时间,而仅有一个SQL语句占用了60%的磁盘读取。通过专注于这些SQL语句,可以提高数据库工作负载高达60%。例如,如果数据库遇到IO瓶颈,专注于一个SQL语句可以节省高达60%的磁盘读取。




您可以利用Excel来进行上述80/20法则分析的模拟,提供SQL工作负载分布的全面概述。这种方法有助于快速评估数据库SQL性能的整体状况,以及优化高负载SQL语句的成本和效益。更进一步的SQL资源频谱分析已集成到我们的Tosska DB Ace for Oracle软件中。

Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

DBAO Inspect SQL – YouTube

如何为SQL Server调优子查询中带有OR条件的SQL语句?

下面示例显示带有EXISTS子查询的SQL语句。如果在DEPARTMENT表的子查询中满足OR条件,SQL会对EMPLOYEE表中的记录进行计数。

select countn(*) from employee a where
exists (select ‘x’ from department b
   where a.emp_id=b.dpt_manager or a.emp_salary=b.dpt_avg_salary
    )

下面是Tosska专有的树结构执行计划,它需要4分29秒才能完成。

该执行计划显示了从EMPLOYEE到全表扫描DEPARTMENT表的嵌套循环,这是整个执行计划的主要问题。因为 SQL Server 无法通过其他连接操作来解决这个OR条件“a.emp_id=b.dpt_manager or a.emp_salary=b.dpt_avg_salary”。

下面我将子查询中的OR条件改写为UNION ALL子查询,子查询中UNION ALL的第一部分表示“a.emp_id=b.dpt_manager”条件,第二部分表示“a.emp_salary=b.dpt_avg_salary”条件,但排除已经满足第一个条件的数据。

select count(*)
from  employee a
where exists ( select ‘x’
        from   department b
        where a.emp_id = b.dpt_manager
        union all
        select  ‘x’
        from   department b
        where ( not ( a.emp_id = b.dpt_manager )
           or b.dpt_manager is null )
           and a.emp_salary = b.dpt_avg_salary )

下面是改写后SQL的执行计划,看起来有点复杂,但现在性能很好,只需要0.447秒。有两个散列匹配连接用于替换原来从EMPLOYEE表到全表扫描DEPARTMENT表的嵌套循环。

虽然最终改写的步骤有点复杂,但这种改写可以由Tosska SQL Tuning Expert for SQL Server自动完成,这表明该改写SQL比原始SQL快了600多倍。

Tosska SQL Tuning Expert (TSES™) for SQL Server® – Tosska Technologies Limited

如何让SQL语句运行得更慢…但让用户的体验更好(Oracle)?

您的最终用户可能会不断抱怨他们的数据库应用程序的某些功能运行缓慢,但您可能会发现,在当前的Oracle和硬件配置中,这些SQL语句已经达到了它们的最大速度。除非您愿意升级硬件,否则可能没有办法改进SQL。有时,为了让用户感觉更好,您不必调优SQL以使其运行得更快,而只需调优SQL以使某些应用程序的SQL语句运行得更慢。

这是一个示例,该SQL用于显示表Emp_sal_hist和表Employee在满足某些条件后的信息。该SQL是在线查询执行的,用户必须等待至少5秒,才能在单击鼠标后在屏幕上显示任何数据。

select * from employee a,emp_sal_hist c
where a.emp_name like ‘A%’
and a.emp_id=c.sal_emp_id
and c.sal_salary<1800000
order by c.sal_emp_id

下面是SQL的执行计划和执行统计,提取全部79374条记录花费了10.41秒,第一条记录返回的反应时间为5.72秒。该查询显示了EMPLOYEE和EMP_SAL_HIST表的MERGE JOIN,在将其合并到最终结果之前,对两个相对应的表进行排序操作。这就是用户必须等待至少5秒才能看到屏幕上显示的内容的原因。

作为条件“a.emp_id = c.sal_emp_id”,我们知道“ORDER BY c.sal_emp_id”和“ORDER BY a.emp_id”是等效的,因为SQL语法改写不能强制对该SQL的执行计划进行指定的操作,所以我添加了一个优化器提示/*+ INDEX(@SEL$1 A EMPLOYEE_PK) */来减少“order by a.emp_id”的排序时间。

SELECT   /*+ INDEX(@SEL$1 A EMPLOYEE_PK) */ *
FROM   employee a,
     emp_sal_hist c
WHERE  a.emp_name LIKE ‘A%’
   AND a.emp_id = c.sal_emp_id
   AND c.sal_salary < 1800000
ORDER BY c.sal_emp_id

虽然在新的执行计划中,总体运行时间增加了3秒,但响应时间从5.72秒减少到1.16秒,因此用户可以更快的看到屏幕上第一页信息。我相信大多数用户不在乎是否还有3秒可以返回所有79374条记录。这就是为什么在管理用户期望时,SQL调优更像一门艺术而不是科学。
这种改写可以由Tosska SQL Tuning Expert Pro for Oracle自动实现。

https://www.tosska.cn/tosska-sql-tuning-expert-pro-tse-pro-for-oracle-zh/

如何调优SQL Server性能不好并且设置返回行数的SQL语句?

在设置返回行数或者使用Top关键字后,某些SQL语句会运行的非常慢。设置返回行数和使用Top关键字会告诉SQL Server从SQL语句中选择特定行数而不是提取所有记录。没有多少人知道在设置返回行数或者使用Top关键字后SQL Server会尝试重新优化您的SQL语句,重新优化后的SQL语句产生的执行计划通常可以更快的检索前几条记录,但是也可能适得其反。

设置返回行数重新优化查询的好示例
下面是一个示例,显示了该SQL从数据库中检索217500行记录需要6.78秒。这是一个好的执行计划,因为它对[DEPARTMENT]和[EMPLOYEE]的两个表扫描进行哈希匹配。

下面屏幕显示了设置返回行数为1后新的执行计划把哈希匹配改为嵌套循环。嵌套循环操作通常提供更快的前几条记录检索时间,但在某些情况下可能不利于整体记录的提取。很高兴看到SQL Server提取此SQL的第一行记录仅用了0.013秒。

设置返回行数重新优化查询的坏示例
让我们来看一个坏示例,它展示了在使用设置返回行数为1后,SQL Server如何将一个好的执行计划变成一个糟糕的执行计划。下面一个示例显示,该SQL从数据库中检索1613行记录花费了0.118秒,虽然该执行计划有点复杂,但对于检索完所有行来说是一个很好的执行计划。

下面屏幕显示了设置返回行数为1后生成的新执行计划,该执行计划现在更改为带有两次表扫描的嵌套循环。新的执行计划提取第一条记录需要1.312秒,比从数据库提取所有行所用的0.118秒还要慢。

如何解决这个问题呢?
我们可以使用提示注入或者SQL语法改写来影响SQL Server为设置返回行数或者Top关键字操作改回原始的执行计划或者生成更好的执行计划。下面是提示注入生成的一个很好的执行计划,它比设置返回行数为1的原始SQL快了90倍。

Tosska SQL Tuning Expert (TSES™) for SQL Server® – Tosska Technologies Limited