enable_remap_hint 查询重写提示
enable_remap_hint 是一个系统变量,用于启用 SQL 查询中的表重写提示(Remap Hint)功能。开启后,你可以通过在 SQL 语句前添加 JSON 格式的注释,将表名映射到自定义的查询语句,从而实现动态查询重写。
功能概述
Remap Hint 功能允许你:
- 虚拟表映射:将不存在的表名映射到实际查询,无需创建视图
- 动态视图替代:在 SQL 中直接定义查询逻辑,灵活性更高
- 聚合查询重写:将简单的表查询重写为复杂的聚合查询
- 多表联合重写:同时对多个表进行查询重写
开启/关闭设置
enable_remap_hint 默认关闭(值为 0)。
- 仅对当前会话开启:
SET enable_remap_hint = 1;
- 全局开启:
SET GLOBAL enable_remap_hint = 1;
- 关闭:
SET enable_remap_hint = 0;
语法格式
/*+ {
"rewrites": {
"database.table_name": "SELECT ... FROM real_table ..."
}
} */
SELECT * FROM table_name;
语法说明
/*+ ... */:Hint 注释格式,必须紧跟在 SQL 语句之前rewrites:JSON 对象,包含表名到查询语句的映射- Key 格式:必须是
database.table格式(包含数据库名) - Value 格式:必须是有效的 SELECT 语句
使用示例
示例 1:单表重写
将表 t1 的查询重写为只返回 a 列:
-- 开启 remap hint
SET enable_remap_hint = 1;
-- 创建测试表
CREATE DATABASE IF NOT EXISTS db1;
USE db1;
CREATE TABLE t1 (a INT, b INT, c INT);
INSERT INTO t1 VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);
-- 使用 remap hint 重写查询
/*+ {"rewrites": {"db1.t1": "SELECT a FROM db1.t1"}} */
SELECT * FROM t1;
结果:
+------+
| a |
+------+
| 1 |
| 4 |
| 7 |
+------+
示例 2:虚拟汇总表
创建一个虚拟的汇总表,映射到聚合查询:
-- 创建销售表(假设当前在 db1 数据库中)
CREATE TABLE sales (
product_id INT,
quantity INT,
sale_date DATE
);
INSERT INTO sales VALUES
(1, 10, '2024-01-01'),
(1, 15, '2024-01-02'),
(2, 20, '2024-01-01'),
(2, 25, '2024-01-02');
-- 虚拟汇总表 - sales_summary 实际不存在
-- hint 将 db1.sales_summary 重写为 db1.sales 的聚合查询
/*+ {
"rewrites": {
"db1.sales_summary": "SELECT product_id, SUM(quantity) AS total_quantity FROM db1.sales GROUP BY product_id"
}
} */
SELECT * FROM db1.sales_summary WHERE total_quantity > 20;
结果:
+------------+----------------+
| product_id | total_quantity |
+------------+----------------+
| 1 | 25 |
| 2 | 45 |
+------------+----------------+
示例 3:多表联合重写
同时对多个表进行重写:
-- 创建订单表和产品表
CREATE TABLE orders (order_id INT, product_id INT, status VARCHAR(20));
CREATE TABLE products (product_id INT, product_name VARCHAR(50), category VARCHAR(20));
INSERT INTO orders VALUES (1, 101, 'completed'), (2, 102, 'pending'), (3, 101, 'completed');
INSERT INTO products VALUES (101, 'Laptop', 'Electronics'), (102, 'Book', 'Education');
-- 同时重写两个表
/*+ {
"rewrites": {
"db1.orders": "SELECT * FROM db1.orders WHERE status = 'completed'",
"db1.products": "SELECT * FROM db1.products WHERE category = 'Electronics'"
}
} */
SELECT o.order_id, p.product_name FROM orders o
JOIN products p ON o.product_id = p.product_id;
结果:
+----------+--------------+
| order_id | product_name |
+----------+--------------+
| 1 | Laptop |
| 3 | Laptop |
+----------+--------------+
示例 4:带条件过滤的重写
使用重写为表添加默认过滤条件:
CREATE TABLE users (id INT, name VARCHAR(50), status VARCHAR(20));
INSERT INTO users VALUES (1, 'Alice', 'active'), (2, 'Bob', 'inactive'), (3, 'Carol', 'active');
-- 将 db1.active_users 映射到只查询活跃用户的查询
/*+ {
"rewrites": {
"db1.active_users": "SELECT * FROM db1.users WHERE status = 'active'"
}
} */
SELECT * FROM db1.active_users;
结果:
+------+-------+--------+
| id | name | status |
+------+-------+--------+
| 1 | Alice | active |
| 3 | Carol | active |
+------+-------+--------+
示例 5:带窗口函数的重写
使用重写实现复杂的窗口函数查询:
CREATE TABLE employee_sales (emp_id INT, department VARCHAR(20), monthly_sales DECIMAL(10,2));
INSERT INTO employee_sales VALUES
(1, 'Sales', 5000.00),
(2, 'Sales', 7000.00),
(3, 'Marketing', 4500.00),
(4, 'Marketing', 6000.00);
-- 使用窗口函数计算部门排名
/*+ {
"rewrites": {
"db1.sales_rank": "SELECT emp_id, department, monthly_sales, RANK() OVER (PARTITION BY department ORDER BY monthly_sales DESC) AS dept_rank FROM db1.employee_sales"
}
} */
SELECT * FROM db1.sales_rank WHERE dept_rank = 1;
结果:
+--------+------------+---------------+-----------+
| emp_id | department | monthly_sales | dept_rank |
+--------+------------+---------------+-----------+
| 4 | Marketing | 6000.00 | 1 |
| 2 | Sales | 7000.00 | 1 |
+--------+------------+---------------+-----------+
错误处理
使用 Remap Hint 时可能遇到以下错误:
| 错误类型 | 错误信息示例 | 解决方法 |
|---|---|---|
| JSON 格式错误 | invalid character 'r' looking for beginning of object key string |
确保 JSON 格式正确,所有 key 和 value 都使用双引号 |
| Key 缺少数据库名 | the mapping name needs to include database name |
Key 必须是 database.table 格式 |
| 空数据库或表名 | empty table or database |
数据库名和表名都不能为空 |
| Value 非 SELECT | only accept SELECT-like statements as rewrites |
Value 必须是 SELECT 语句 |
| 引用不存在的表 | table "xxx" does not exist |
确保 Value 中引用的表存在 |
| SQL 语法错误 | You have an error in your SQL syntax |
检查 Value 中的 SQL 语法 |
限制条件
- 只支持 SELECT 语句:Remap Hint 仅对 SELECT 语句生效,INSERT、UPDATE、DELETE 等其他语句会被忽略
- Key 必须包含数据库名:格式必须是
database.table,不能只写表名 - Value 必须是 SELECT 语句:不能是 DDL 或其他 DML 语句
- 不支持递归重写:重写目标中的表不会再次被重写
- 注释格式:只支持
/*+ */格式
应用场景
- 快速原型开发:无需创建视图,直接在 SQL 中定义虚拟表
- 动态报表:根据需要动态调整查询逻辑
- 数据抽象:为复杂查询创建简单的表别名
- 测试和调试:临时替换表数据源进行测试
- 性能优化:将宽表查询重写为只查询需要的列