# 慢SQL优化最佳实践
#### 应用场景
慢SQL是数据库性能问题的常见原因，执行时间过长的SQL语句会占用大量系统资源，导致业务响应缓慢甚至超时。华为云GaussDB提供了慢SQL优化功能，帮助用户识别和优化慢SQL语句，从而提升数据库性能。
本文通过以下四个案例，介绍如何使用GaussDB慢SQL功能定位并解决常见的性能问题。
- [案例一：全表扫描优化]
- [案例二：索引选择优化]
- [案例三：高频SQL限流保护]
- [案例四：危险SQL紧急拦截]
 
#### 前提条件
已购买GaussDB实例，且实例状态为"正常"。
#### 构造数据
1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
2. 在"实例管理"页面，选择指定的实例，单击实例名称，进入实例基本信息页面。
3. 在左侧导航栏单击"参数管理"，进入"参数"页面。
4. 单击"高风险参数"，在搜索框中搜索参数"log_min_duration_statement"，修改参数值为0。 
   log_min_duration_statement参数用于控制慢SQL的阈值，默认将查询时间超过3s的SQL视为慢SQL。如果业务需要将查询时间低于3s的SQL视为慢SQL，则需要修改该参数。为便于演示SQL性能优化效果，本实践将该参数设置为0。
   图1修改参数值   
   ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002625366393.png "点击放大")
   
   
   
5. 登录数据库，预置表和数据。本文以通过DAS登录数据库的方式为例。 
   1. 在实例基本信息页面右上角，单击"登录"，进入数据管理服务数据库登录界面。
   
   2. 在自定义登录页面正确输入对应用户名的密码，单击"测试连接"。测试连接通过后，单击"登录"，进入您的数据库。
   
   3. 在顶部菜单栏选择"SQL操作"\>"SQL窗口"，打开一个SQL窗口。
   
   4. 输入如下SQL，创建用户。
      ```
      CREATE USER 用户名 WITH CREATEDB PASSWORD '用户密码';
      ```
      
   
   5. 使用[5.d]创建的用户名按照[5.a]\~[5.b]重新登录数据库。
   
   6. 在首页单击"新建数据库"，输入数据库名称，选择DBCOMPATIBILITY，单击"确定"。本实践中选择使用PostgreSQL作为兼容的数据库类型。
      图2新建数据库   
      ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002594766902.png "点击放大")
      
      
   
   7. 数据库创建完成后，在顶部菜单栏选择"库管理"，并在库管理界面切换为[5.f]创建的数据库，单击"新建Schema"，输入Schema名称，单击"确定"。
      图3新建Schema   
      ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002594766892.png "点击放大")
      
      
   
   8. 在顶部菜单栏选择"SQL操作"\>"SQL窗口"，打开一个SQL窗口，在左边切换库名为[5.f]创建的数据库，切换Schema为[5.g]创建的Schema。
   
   9. 执行如下SQL，预置表和数据以模拟业务场景。 模拟数据不考虑真实性，仅用于演示。
      1. 创建用户表和模拟数据。
         ```
         -- 1. 用户表 (users)
         CREATE TABLE IF NOT EXISTS users (
             id BIGSERIAL PRIMARY KEY,
             username VARCHAR(50) NOT NULL,
             email VARCHAR(100) NOT NULL,
             phone VARCHAR(20),
             status VARCHAR(20) DEFAULT 'active',
             create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
             updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
         COMMENT ON TABLE users IS '用户表';
         COMMENT ON COLUMN users.id IS '用户ID，主键';
         COMMENT ON COLUMN users.username IS '用户名';
         COMMENT ON COLUMN users.email IS '邮箱地址';
         COMMENT ON COLUMN users.phone IS '手机号码';
         COMMENT ON COLUMN users.status IS '用户状态：active/inactive/banned';
         COMMENT ON COLUMN users.create_time IS '创建时间';
         COMMENT ON COLUMN users.updated_time IS '更新时间';
         -- 生成 users 表的模拟数据
         INSERT INTO users (username, email, phone, status, create_time)
         SELECT
             'user_' || i AS username,
             'user_' || i || '@example.com' AS email,
             '138' || LPAD(i::TEXT, 8, '0') AS phone,
             CASE 
                 WHEN i % 100 = 0 THEN 'banned'
                 WHEN i % 10 = 0 THEN 'inactive'
                 ELSE 'active' 
             END AS status,
             NOW() - (FLOOR(RANDOM() * 365) || ' days')::INTERVAL
         FROM generate_series(1, 3000000) AS t(i);
         ```
         
      
      2. 创建订单表和模拟数据。
         ```
         -- 2. 订单表 (orders)
         CREATE TABLE IF NOT EXISTS orders (
             id BIGSERIAL PRIMARY KEY,
             order_no VARCHAR(50) NOT NULL UNIQUE,
             user_id BIGINT NOT NULL,
             customer_name VARCHAR(100),
             total_amount DECIMAL(12, 2) DEFAULT 0.00,
             status VARCHAR(20) DEFAULT 'pending',
             payment_status VARCHAR(20) DEFAULT 'unpaid',
             create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
             updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
         COMMENT ON TABLE orders IS '订单表';
         COMMENT ON COLUMN orders.id IS '订单ID，主键';
         COMMENT ON COLUMN orders.order_no IS '订单编号';
         COMMENT ON COLUMN orders.user_id IS '用户ID';
         COMMENT ON COLUMN orders.customer_name IS '客户姓名';
         COMMENT ON COLUMN orders.total_amount IS '订单总金额';
         COMMENT ON COLUMN orders.status IS '订单状态：pending/completed/cancelled/refunded';
         COMMENT ON COLUMN orders.payment_status IS '支付状态：paid/unpaid';
         COMMENT ON COLUMN orders.create_time IS '创建时间';
         COMMENT ON COLUMN orders.updated_time IS '更新时间';
         -- 生成 orders 表的模拟数据
         INSERT INTO orders (order_no, user_id, customer_name, total_amount, status, payment_status, create_time)
         SELECT
             'ORD' || LPAD(i::TEXT, 10, '0') AS order_no,
             (RANDOM() * 3000000)::BIGINT + 1 AS user_id,
             'customer_' || ((RANDOM() * 3000000)::BIGINT + 1) AS customer_name,
             ROUND((RANDOM() * 10000 + 100)::DECIMAL(12, 2), 2) AS total_amount,
             CASE
                 WHEN i % 100 = 0 THEN 'refunded'
                 WHEN i % 7 = 0 THEN 'cancelled'
                 WHEN i % 5 = 0 THEN 'completed'
                 ELSE 'pending'
             END AS status,
             CASE
                 WHEN (CASE
                     WHEN i % 100 = 0 THEN 'refunded'
                     WHEN i % 7 = 0 THEN 'cancelled'
                     WHEN i % 5 = 0 THEN 'completed'
                     ELSE 'pending'
                 END) = 'completed' THEN 'paid'
                 ELSE 'unpaid'
             END AS payment_status,
             NOW() - (FLOOR(RANDOM() * 365) || ' days')::INTERVAL AS create_time
         FROM generate_series(1, 5000000) AS t(i);
         ```
         
      
      3. 创建订单明细表和模拟数据。
         ```
         -- 3. 订单明细表 (order_items)
         CREATE TABLE IF NOT EXISTS order_items (
             id BIGSERIAL PRIMARY KEY,
             order_id BIGINT NOT NULL,
             product_id BIGINT,
             product_name VARCHAR(200),
             quantity INT DEFAULT 1,
             unit_price DECIMAL(10, 2),
             total_price DECIMAL(12, 2),
             create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
             updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
         COMMENT ON TABLE order_items IS '订单明细表';
         COMMENT ON COLUMN order_items.id IS '订单明细ID，主键';
         COMMENT ON COLUMN order_items.order_id IS '订单ID';
         COMMENT ON COLUMN order_items.product_id IS '商品ID';
         COMMENT ON COLUMN order_items.product_name IS '商品名称';
         COMMENT ON COLUMN order_items.quantity IS '购买数量';
         COMMENT ON COLUMN order_items.unit_price IS '单价';
         COMMENT ON COLUMN order_items.total_price IS '总价';
         COMMENT ON COLUMN order_items.create_time IS '创建时间';
         COMMENT ON COLUMN order_items.updated_time IS '更新时间';
         -- 生成 order_items 表的模拟数据
         INSERT INTO order_items (order_id, product_id, product_name, quantity, unit_price, total_price)
         SELECT
             order_id,
             product_id,
             product_name,
             quantity,
             unit_price,
             ROUND(unit_price * quantity, 2) AS total_price
         FROM (
             SELECT
                 (RANDOM() * 5000000)::BIGINT + 1 AS order_id,
                 (RANDOM() * 1000000)::INTEGER + 1 AS product_id,
                 'product_' || ((RANDOM() * 100)::INTEGER + 1) AS product_name,
                 (RANDOM() * 5)::INTEGER + 1 AS quantity,
                 ROUND((RANDOM() * 500 + 10)::DECIMAL(10, 2), 2) AS unit_price
             FROM generate_series(1, 2000000)
         ) AS t;
         ```
         
      
      4. 创建商品表和模拟数据。
         ```
         -- 4. 商品表 (products)
         CREATE TABLE IF NOT EXISTS products (
             id BIGSERIAL PRIMARY KEY,
             product_name VARCHAR(200) NOT NULL,
             category VARCHAR(50),
             price DECIMAL(10, 2) DEFAULT 0.00,
             sales INT DEFAULT 0,
             stock INT DEFAULT 0,
             status VARCHAR(20) DEFAULT 'available',
             create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
             updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
         COMMENT ON TABLE products IS '商品表';
         COMMENT ON COLUMN products.id IS '商品ID，主键';
         COMMENT ON COLUMN products.product_name IS '商品名称';
         COMMENT ON COLUMN products.category IS '商品分类';
         COMMENT ON COLUMN products.price IS '商品价格';
         COMMENT ON COLUMN products.sales IS '销售数量';
         COMMENT ON COLUMN products.stock IS '库存数量';
         COMMENT ON COLUMN products.status IS '商品状态';
         COMMENT ON COLUMN products.create_time IS '创建时间';
         COMMENT ON COLUMN products.updated_time IS '更新时间';
         -- 生成 products 表的模拟数据
         INSERT INTO products (product_name, category, price, sales, stock, status)
         SELECT
             CASE
                 WHEN category_val = 'Electronics' THEN
                     CASE
                         WHEN i % 10 = 0 THEN '手机品牌A' || i
                         WHEN i % 10 = 1 THEN '手机品牌B' || i
                         WHEN i % 10 = 2 THEN '手机品牌C' || i
                         ELSE '电子产品_' || i
                     END
                 ELSE category_val || '_product_' || i
             END AS product_name,
             category_val,
             ROUND((RANDOM() * 5000 + 50)::DECIMAL(10, 2), 2) AS price,
             (RANDOM() * 10000)::INTEGER AS sales,
             (RANDOM() * 5000)::INTEGER AS stock,
             'available' AS status
         FROM (
             SELECT
                 i,
                 CASE
                     WHEN i % 4 = 0 THEN 'Electronics'
                     WHEN i % 4 = 1 THEN 'Clothing'
                     WHEN i % 4 = 2 THEN 'Food'
                     ELSE 'Home'
                 END AS category_val
             FROM generate_series(1, 5000000) AS t(i)
         ) temp;
         ```
         
       
   
   
   
   
 
#### 典型案例
- [案例一：全表扫描优化]
  
  **问题场景**
  在电商系统中，用户频繁查询近期待处理的订单，导致订单表数据量达到数百万行，查询响应缓慢，进而影响订单处理效率。
  **问题SQL**
  ```
  SELECT order_no, total_amount, customer_name
  FROM orders
  WHERE create_time >= '2025-05-01'
    AND status = 'pending'
  ORDER BY create_time DESC
  LIMIT 100;
  ```
  **问题分析**
  1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
  
  2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
  
  3. 单击"诊断优化 \> SQL诊断"。
  
  4. 在"慢SQL"页签，选择指定节点、时间范围、SQL文本，配置SQL阈值，单击"查询"按钮，获取慢SQL列表。
     - 用户可自行选择时间区间，最大时间跨度为一天，可按照节点维度展示数据。
     
     - 过滤系统用户：开启后，将会跳过系统用户所执行的SQL记录。默认开启。
     
     - 用户可以选择"OR"或者"AND"查询，筛选框中可以填入需要组合过滤的多个SQL文本（不超过5个）。本示例中选择"OR"查询，SQL文本为 orders。
     
     - 支持自定义慢SQL阈值筛选。本示例中配置为1000ms。
     
     
     图4查询慢SQL   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002594926804.png "点击放大")
     
     
  
  5. 在慢SQL列表中，查看SQL计划（执行计划）和平均执行时间。平均时间为2.0286s，执行计划如下。
     ```
     [Parameterized]
     Datanode Name: dn_6001_6002_6003
     Limit  (cost=257646.18..257646.30 rows=50 width=44)
       ->  Sort  (cost=257646.18..266236.99 rows=50 width=44)
             Sort Key: create_time DESC
             ->  Seq Scan on orders  (cost=0.00..143494.00 rows=3436323 width=44)
                   Filter: (((status)::text = '***'::text) AND (create_time >= '***'::timestamp without time zone)), (Expression Flatten Optimized)
     ```
     执行计划中，Seq Scan on orders表示对整张orders表进行全表顺序扫描，遍历3436323行数据，每一行数据读取出来后，通过Filter过滤status和create_time两个条件，以获取符合条件的数据行。由于是扫描全部数据行后才进行过滤和排序，因此效率极低。
     
  
  
  **优化方案**
  通过对执行计划的分析，该SQL扫描了整张orders表，并过滤出符合status和create_time两个条件的数据行，因此需要对这两个条件字段添加联合索引。注意联合索引字段的顺序，顺序错误可能会引起索引失效。
  ```
  CREATE INDEX idx_orders_status_create_time ON orders(status, create_time DESC);
  ```
  **验证效果**
  1. 重新执行SQL。
     ```
     SELECT order_no, total_amount, customer_name
     FROM orders
     WHERE create_time >= '2025-05-01'
       AND status = 'pending'
     ORDER BY create_time DESC
     LIMIT 100;
     ```
     
  
  2. 查看执行计划和时间。执行时间为0.001s，执行计划如下。
     图5查看SQL计划和执行时间   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002594766888.png "点击放大")
     
     执行计划：
     ```
     [Parameterized]
     Datanode Name: dn_6001_6002_6003
     Limit  (cost=0.00..2.32 rows=50 width=44)
       ->  Index Scan using idx_orders_status_create_time on orders  (cost=0.00..159532.64 rows=50 width=44)
             Index Cond: (((status)::text = '***'::text) AND (create_time >= '***'::timestamp without time zone))
     ```
     从执行计划中可以看到，SQL命令采用了索引扫描：Index Scan，且与优化前执行计划中使用Filter不同，优化后的执行计划采用Index Cond，过滤逻辑直接在索引层面完成，无需将整行数据取出来后再Filter，因此执行效率显著提升。
     
  
  3. 对比优化前后指标。可以看到执行速度得到了显著提升。
     
     | 指标        | 优化前 | 优化后 | 提升     |
     |:---|:---|:---|:---|
     | 扫描方式     | Seq Scan                                                     | Index Scan                                                  | -        |
     | 平均执行时间 | 2.0286s                                                         | 0.001s                                                       | 2028.6 倍 |
        
     
   
- [案例二：索引选择优化]
  
  **问题场景**
  在电商平台中，用户查看自己的历史订单列表时，需要展示订单基本信息以及最后一条订单明细的商品名称。数据库已为orders表创建了id主键索引，但未创建user_id索引。查询过程中，优化器选择按主键索引进行反向扫描（期望利用ORDER BY id DESC的有序性），导致需要大量Filter过滤user_id条件，页面加载缓慢，影响用户体验。
  **问题SQL**
  ```
  SELECT o.order_no, o.total_amount, o.customer_name, o.status, o.create_time,
         (SELECT oi.product_name FROM order_items oi WHERE oi.order_id = o.id AND ROWNUM = 1 ORDER BY oi.id DESC) as last_product
  FROM orders o
  WHERE o.user_id = 12345
  ORDER BY o.id DESC
  LIMIT 20;
  ```
  **问题分析**
  1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
  
  2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
  
  3. 单击"诊断优化 \> SQL诊断"。
  
  4. 在"慢SQL"页签，选择指定节点、时间范围、SQL文本，配置SQL阈值，单击"查询"按钮，获取慢SQL列表。
     - 用户可自行选择时间区间，最大时间跨度为一天，可按照节点维度展示数据。
     
     - 过滤系统用户：开启后，将会跳过系统用户所执行的SQL记录。默认开启。
     
     - 用户可以选择"OR"或者"AND"查询，筛选框中可以填入需要组合过滤的多个SQL文本（不超过5个）。本示例中选择"OR"查询，SQL文本为 orders。
     
     - 支持自定义慢SQL阈值筛选。本示例中配置为1000ms。
     
     
     图6查询慢SQL   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002634453126.png "点击放大")
     
     
  
  5. 在慢SQL列表中，查看SQL计划（执行计划）和平均执行时间。平均时间为2.1985s，执行计划如下。
     ```
     [Parameterized]
     Datanode Name: dn_6001_6002_6003
     Limit  (cost=176666.67..176666.67 rows=1 width=61)
       ->  Index Scan Backward using orders_pkey on orders o  (cost=0.00..176666.67 rows=1 width=61)
             Filter: (user_id = $2)
             SubPlan 1
               ->  Sort  (cost=0.01..0.02 rows=1 width=18)
                     Sort Key: oi.id DESC
                     ->  Rownum  (cost=0.00..0.00 rows=1 width=18)
                           StopKey: (ROWNUM = $1)
                           ->  Seq Scan on order_items oi  (cost=0.00..47983.00 rows=1 width=18)
                                 Filter: (order_id = o.id), (Expression Flatten Optimized)
     ```
     从执行计划可以看出，优化器选择按主键索引反向扫描（Index Scan Backward using orders_pkey），期望利用id DESC有序性避免排序。但WHERE条件是user_id，需要回表+Filter过滤，实际扫描500万行才找到几条匹配记录，效率极低。子查询中Seq Scan on order_items表明对order_items进行了全表扫描，过滤条件 Filter: order_id = o.id，加剧了SQL执行开销。
     
  
  
  **优化方案**
  **方案一：SQL Patch强制全表扫描**
  优化器错误选择主键索引反向扫描，导致大量Filter过滤。通过SQL Patch强制使用全表扫描做临时规避，顺序扫描效率反而会更高。
  1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
  
  2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
  
  3. 单击"诊断优化 \> SQL诊断"。
  
  4. 在"慢SQL"页签，选择指定节点，时间范围，组合过滤SQL文本、归一化SQL ID以及其他扩展字段，单击"查询"按钮，获取慢SQL列表。
  
  5. 在慢SQL列表，选择对应慢SQL，在"操作"列单击"更多 \> SQL Patch"，显示"SQL PATCH详情"页面。
     图7创建SQL PATCH   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002664892195.png "点击放大")
     
     
  
  6. 选择PATCH类型为HINT，输入PATCH名称和PATCH内容，单击"创建"。
     图8创建SQL PATCH   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002664892191.png "点击放大")
     
     
  
  7. 验证效果。
     1. 重新执行如下SQL。
        ```
        SELECT o.order_no, o.total_amount, o.customer_name, o.status, o.create_time,
               (SELECT oi.product_name FROM order_items oi WHERE oi.order_id = o.id AND ROWNUM = 1 ORDER BY oi.id DESC) as last_product
        FROM orders o
        WHERE o.user_id = 12345
        ORDER BY o.id DESC
        LIMIT 20;
        ```
        
     
     2. 查看执行计划和时间。执行时间为1.0434s，执行计划如下。
        图9查看SQL计划和执行时间   
        ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002664732249.png "点击放大")
        
        执行计划：
        ```
        [Parameterized]
        Datanode Name: dn_6001_6002_6003
        Limit  (cost=178977.03..178977.03 rows=1 width=61)
          ->  Sort  (cost=178977.03..178977.03 rows=1 width=61)
                Sort Key: o.id DESC
                ->  Seq Scan on orders o  (cost=0.00..178977.02 rows=1 width=61)
                      Filter: (user_id = '***'), (Expression Flatten Optimized)
                      SubPlan 1
                        ->  Sort  (cost=47983.01..47983.01 rows=1 width=18)
                              Sort Key: oi.id DESC
                              ->  Rownum  (cost=0.00..47983.00 rows=1 width=18)
                                    StopKey: (ROWNUM = '***')
                                    ->  Seq Scan on order_items oi  (cost=0.00..47983.00 rows=1 width=18)
                                          Filter: (order_id = o.id), (Expression Flatten Optimized)
        ```
        执行计划强制使用全表扫描（Seq Scan），避免了大量回表和Filter过滤操作。在高负载场景下，暂时无法创建更优索引时，可使用SQL Patch作为临时调优手段。
        
      
  
  8. 对比优化前后指标。可以看到执行速度得到了有效提升。
     
     | 指标     | 优化前                 | 优化后     | 提升   |
     |:---|:---|:---|:---|
     | 扫描方式  | Index Scan Backward | Seq Scan | -    |
     | 执行时间 | 2.1985s             | 1.0434s  | 2.11倍 |
        
     
  
  
  **方案二：创建最优复合索引**
  - orders表没有user_id、id相关索引，导致必须全表扫描，再筛选、排序。
  
  - order_items没有order_id + id + product_name索引，子查询只能用主键反向扫描+大量回表，无法快速定位当前订单的商品。
  
  
  在业务非高负载期间，可以通过分析执行计划来创建更优的索引。
  1. 创建如下复合索引。
     ```
     -- 1. 解决 orders 全表扫描 + 额外排序
     CREATE INDEX idx_orders_user_id_id ON orders(user_id, id DESC);
     -- 2. 解决子查询慢，消除低效扫描
     CREATE INDEX idx_order_items_order_id_id_product_name ON order_items(order_id, id DESC, product_name);
     ```
     
  
  2. 对于指定的慢SQL，检查是否存在已创建的SQL Patch，若存在需关闭或删除SQL Patch。
     1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
     
     2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
     
     3. 单击"诊断优化 \> SQL诊断"。
     
     4. 在"慢SQL"页签，选择指定节点，时间范围，组合过滤SQL文本、归一化SQL ID以及其他扩展字段，单击查询按钮，获取慢SQL列表。
     
     5. 在慢SQL列表，选择对应慢SQL，在"操作"列单击"更多 \> SQL Patch"。
        图10查看SQL Patch详情   
        ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002664732255.png "点击放大")
        
        
     
     6. 如果已创建SQL PATCH，单击![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002634613058.png "点击放大")按钮关闭SQL Patch，或单击"删除"按钮直接删除SQL Patch。
        图11关闭/删除SQL Patch   
        ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002634613054.png "点击放大")
        
        
      
  
  3. 验证效果。
     1. 重新执行SQL语句。
        ```
        SELECT o.order_no, o.total_amount, o.customer_name, o.status, o.create_time,
               (SELECT oi.product_name FROM order_items oi WHERE oi.order_id = o.id AND ROWNUM = 1 ORDER BY oi.id DESC) as last_product
        FROM orders o
        WHERE o.user_id = 12345
        ORDER BY o.id DESC
        LIMIT 20;
        ```
        
     
     2. 执行完后得到如下的SQL详情。执行时间为0.001s，执行计划如下。
        图12查看SQL计划和执行时间   
        ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002664892187.png "点击放大")
        
        执行计划：
        ```
        [Parameterized]
        Datanode Name: dn_6001_6002_6003
        Limit  (cost=0.00..3.54 rows=1 width=61)
          ->  Index Scan using idx_orders_user_id_id on orders o  (cost=0.00..3.54 rows=1 width=61)
                Index Cond: (user_id = '***')
                SubPlan 1
                  ->  Rownum  (cost=0.00..1.27 rows=1 width=18)
                        StopKey: (ROWNUM = '***')
                        ->  Index Only Scan using idx_order_items_order_id_id_product_name on order_items oi  (cost=0.00..1.27 rows=1 width=18)
                              Index Cond: (order_id = o.id)
        ```
        总耗时从2.1985s降至0.001s，执行效率提升2198.5倍。orders表从主键全扫描+Filter改为索引查找，order_items子查询实现了仅索引扫描（Index Only Scan）， 避免了回表操作和全表顺序扫描，大幅降低了随机 I/O 和总查询成本，远超未添加索引时的查询效率。
        
      
   
- [案例三：高频SQL限流保护]
  
  **问题场景**
  电商平台进行大促活动期间，某爆款商品页面被大量用户频繁访问。后台持续执行查询商品库存的SQL，每秒执行次数超过10000次，导致数据库CPU使用率飙升至90%+。该SQL属于并发型高危慢SQL，高频执行会导致数据库资源被大量占用，从而引起其他正常业务（如订单提交、支付）响应缓慢甚至超时。
  **问题SQL**
  ```
  SELECT id, product_name, price, stock, status
  FROM products
  WHERE id = 991015 and status = 'available' and stock > 0;
  ```
  **问题表现**
  
  | 指标      | 正常时期    | 大促时期     |
  |:---|:---|:---|
  | SQL执行频率 | 50次/秒 | 10000次/秒 |
  | CPU使用率     | 30%  | 90%+     |
  | 其他业务响应   | 正常    | 超时      |
     
  **优化方案**
  通过GaussDB的SQL限流功能，限制SQL的并发执行数，以防止数据库被压垮。
  1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
  
  2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
  
  3. 单击"诊断优化 \> SQL诊断"。
  
  4. 在"慢SQL"页签，选择指定节点、时间范围、SQL文本，配置SQL阈值，单击"查询"按钮，获取慢SQL列表。
  
  5. 在慢SQL列表，选中执行的SQL，单击"创建SQL限流任务"。
     图13创建SQL限流任务   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002594766890.png "点击放大")
     
     
  
  6. 填写限流任务名称，按当前的实际情况填写并发数，选择限流生效时间，输入"YES"，随后单击"创建"下发SQL限流任务。
     图14创建SQL限流任务   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002625366401.png "点击放大")
     
     
   
  **验证效果**
  本案例中将并发数设置为200，同一时刻该SQL最多同时执行200次，超过限制时将报错拦截，以防止在业务高峰期时，并发型高危慢SQL导致其他正常业务（如订单提交、支付）响应缓慢甚至超时。
  ```
  【执行SQL：(1)】
  SELECT id, product_name, price, stock, status
  FROM products
  WHERE id = 991015 and status = 'available' and stock > 0;
  执行失败，失败原因：[***:52656/***:8635] ERROR: The workload rule takes effect and this request will be cancelled. rule_id: 1, rule_name: "sql-limit"
  ```
- [案例四：危险SQL紧急拦截]
  
  **问题场景**
  某电商后台管理系统新上线了"订单统计导出"功能，用户选择"导出全部订单"时，SQL缺少分页限制，一次性查询几百万条订单数据。该SQL首次执行时导致数据库内存耗尽（OOM），严重时可能触发实例宕机，影响全部业务。运维人员需要立即拦截该高危慢SQL，防止再次执行，但业务代码修复需要走发布流程（预计2小时），期间需用ABORT补丁紧急止损。
  **问题SQL**
  ```
  SELECT u.username, u.email, o.order_no, o.total_amount, o.customer_name, o.status, o.create_time
  FROM orders o
  LEFT JOIN users u ON o.user_id = u.id
  WHERE o.create_time >= '2025-01-01'
  ORDER BY o.create_time DESC;
  -- 缺少 LIMIT，一次性返回几百万条数据
  ```
  **问题表现**
  
  | 指标      | 执行前   | 执行时        | 执行后       |
  |:---|:---|:---|:---|
  | 数据库内存 | 正常 | 耗尽（OOM）   | 严重时实例宕机  |
  | 业务影响   | 无    | 业务中断/执行慢 | 全部业务无法执行 |
  | 故障类型   | 无     | 内存溢出崩溃   | 内存溢出崩溃   |
     
  **优化方案**
  通过GaussDB服务SQL Patch的ABORT功能，禁止该SQL执行，并提前报错返回，从而避免再次触发崩溃。
  1. [登录云数据库GaussDB控制台](https://console.huaweicloud.com/gaussdb/?locale=zh-cn#/gaussdb/management/list)。
  
  2. 在"实例管理"页面，选择指定的实例，单击实例的名称，进入实例详情页面。
  
  3. 单击"诊断优化 \> SQL诊断"。
  
  4. 在"慢SQL"页签，用户可按需选择指定节点，时间范围，SQL文本，SQL阈值，单击查询按钮，获取慢SQL列表。
  
  5. 在慢SQL列表找到执行的SQL，下拉更多，找到SQL Patch。
     图15创建SQL Patch   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002625366397.png "点击放大")
     
     
  
  6. 选择PATCH类型为ABORT，输入PATCH名称，单击创建。
     图16配置SQL PATCH   
     ![](https://support.huaweicloud.com/bestpractice-gaussdb/figure/zh-cn_image_0000002625286265.png "点击放大")
     
     
  
  
  **验证效果**
  重新执行SQL语句，会被限制住：
  ```
  【执行SQL：(1)】
  SELECT u.username, u.email, o.order_no, o.total_amount, o.customer_name, o.status, o.create_time
  FROM orders o
  LEFT JOIN users u ON o.user_id = u.id
  WHERE o.create_time >= '2025-01-01'
  ORDER BY o.create_time DESC;
  执行失败，失败原因：[***:52656/***:8635] ERROR: Statement 1858775530 canceled by abort patch test2
  ```
  禁止该SQL执行，提前报错返回，避免再次触发崩溃。
