报表 SQL 外套 select count(*) 页面超时、Navicat 偶发快

  • 租户:mysql001(32C64G,单租户混部 TP + 报表)

  • 表:orders(2 亿行,按 create_date RANGE 分区 60 个,含 statususer_idmerchant_id 索引)

  • 报表原句(简化):

sql

sql

SELECT merchant_id, SUM(amount), COUNT(DISTINCT user_id)
FROM orders
WHERE create_date >= DATE '2026-01-01'
  AND create_date <  DATE '2026-08-01'
  AND status IN (1,2,3)
GROUP BY merchant_id;
  • 业务层外套总数:

sql

sql

SELECT COUNT(*) FROM (
  SELECT merchant_id, SUM(amount), COUNT(DISTINCT user_id)
  FROM orders
  WHERE create_date >= DATE '2026-01-01'
    AND create_date <  DATE '2026-08-01'
    AND status IN (1,2,3)
  GROUP BY merchant_id
) x;
  • 现象:页面触发 120s 超时;Navicat 直连 2881 偶发 10~20s 出结果,偶发也超时gv$sql_auditelapsed_time 经常 130s+,execute_time 80~120s,queue_time 有时 20~40s。
4 个赞

1)紧急恢复:绑定好计划(Outline)

先用 obclient 直连跑出“快的那次”计划,提 Hint 固化:

sql

sql

CREATE OUTLINE ol_report_orders_count
ON SELECT COUNT(*) FROM (
  SELECT /*+ PARALLEL(8) PARTITION_BATCHED_JOIN() */ merchant_id, SUM(amount), COUNT(DISTINCT user_id)
  FROM orders
  WHERE create_date >= DATE '2026-01-01' AND create_date < DATE '2026-08-01'
    AND status IN (1,2,3)
  GROUP BY merchant_id
) x;

或更直接:

sql

sql

SELECT /*+ PARALLEL(8) */ COUNT(*) FROM ( 原报表SQL ) x;

验证:

sql

sql

SELECT * FROM oceanbase.gv$outline WHERE outline_name='ol_report_orders_count';

2)根治统计信息 + 动态采样

sql

sql

CALL dbms_stats.gather_table_stats('test','orders', degree=>8, granularity=>'PARTITION');
-- 若仍估行歪,SQL 级强制动态采样
SELECT /*+ DYNAMIC_SAMPLING(4) */ COUNT(*) FROM ( 报表SQL ) x;

3)改写 SQL(最稳)

外层 COUNT(*) 对报表无意义,前端分页即可;非要总数:

sql

sql

-- 轻量总数(走索引覆盖)
SELECT COUNT(*) FROM orders
WHERE create_date >= DATE '2026-01-01'
  AND create_date <  DATE '2026-08-01'
  AND status IN (1,2,3);

报表主体走 GROUP BY 直接返回,不套壳。

4)避开 compaction 毛刺

  • 低峰期手动 ALTER SYSTEM MAJOR FREEZE; 后再跑报表

  • 租户级限制报表并发:ALTER SYSTEM SET ob_sql_work_area_percentage=... 或建 resource_group 把报表 SQL 绑低优先级组

5)会话级超时与并行度解耦

JDBC 连接池对报表数据源单独设:

sql

sql

SET SESSION ob_query_timeout = 300000000;
SET SESSION parallel_degree_policy = AUTO;
SET SESSION ob_px_parallel_degree = 8;
1 个赞

够细致,都是干货,学习了

看看看看