在OceanBase中,查看SQL是否走索引最直接的方法就是分析执行计划。以下是详细的操作步骤,从简单到专业,帮你彻底掌握这个技能。
一、核心判断方法:分析执行计划
第1步:获取SQL的执行计划
使用EXPLAIN命令查看SQL的执行计划,这是最关键的一步:
sql
-- 方法1:基础执行计划(快速判断)
EXPLAIN SELECT * FROM users WHERE user_id = 1001;
-- 方法2:详细执行计划(推荐,信息更全)
EXPLAIN EXTENDED SELECT * FROM orders WHERE customer_id = 200 AND amount > 1000;
-- 方法3:JSON格式(最详细,适合复杂分析)
EXPLAIN FORMAT = JSON SELECT * FROM products WHERE category = 'electronics' AND price < 500;
第2步:解读执行计划中的关键信息
查看执行计划输出,重点关注以下两点:
1. 看OPERATOR列:
-
如果显示
TABLE SCAN→ 没有走索引,正在全表扫描 -
如果显示
INDEX SCAN或INDEX SEEK→ 走了索引 -
如果显示
TABLE GET→ 通常是通过主键等值访问,也属于索引访问的一种
2. 看NAME列:
-
如果
NAME显示表名(别名)如users(t1)→ 全表扫描 -
如果
NAME显示表名(别名)索引名如users(t1),idx_user_id→ 使用了名为idx_user_id的索引
第3步:实际案例对比
案例1:没有走索引的情况
sql
EXPLAIN SELECT * FROM employees WHERE email = 'zhangsan@company.com';
输出可能类似:
text
==================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
--------------------------------------------------
|0 |TABLE SCAN |employees(emp)|1 |1056 |
==================================================
结论 :看到TABLE SCAN,说明没有走索引,进行了全表扫描。
案例2:走了索引的情况
sql
-- 假设在user_id上有索引
EXPLAIN SELECT * FROM users WHERE user_id = 1001;
输出可能类似:
text
=======================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
-------------------------------------------------------
|0 |TABLE GET |users(u) |1 |53 |
=======================================================
或者:
text
===============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
---------------------------------------------------------------
|0 |INDEX SCAN |users(u),idx_user_id |1 |46 |
|1 | TABLE GET |users(u) |1 |53 |
===============================================================
结论 :看到INDEX SCAN或TABLE GET(通过主键访问),说明走了索引。
二、进阶诊断:为什么没走索引?
如果发现SQL没走索引,可以按以下步骤排查:
第1步:检查表上是否存在相关索引
sql
-- 查看表的索引信息
SHOW INDEX FROM 表名;
-- 或使用更详细的查询
SELECT
table_name,
index_name,
column_name,
seq_in_index
FROM information_schema.statistics
WHERE table_schema = '你的数据库名'
AND table_name = '你的表名'
ORDER BY index_name, seq_in_index;
第2步:检查索引是否适合当前查询
sql
-- 查看表的创建语句,了解索引结构
SHOW CREATE TABLE 表名;
常见问题:
-
查询条件与索引列不匹配 :例如索引是
(a, b),但查询只用了b -
使用了函数或表达式 :
WHERE UPPER(name) = 'ABC'不会使用name上的普通索引 -
隐式类型转换 :字符串列用数字查询
WHERE id = '123'可能导致索引失效
第3步:检查统计信息是否准确
sql
-- 查看表的统计信息
SELECT
table_name,
table_rows,
avg_row_length,
data_length,
index_length,
update_time
FROM information_schema.tables
WHERE table_schema = '你的数据库名'
AND table_name = '你的表名';
-- 如果怀疑统计信息过时,可以手动收集(在业务低峰期操作)
ANALYZE TABLE 表名 UPDATE STATISTICS;
三、专业方法:查看已执行SQL的实际执行计划
对于已经在运行的SQL,可以查看其实际使用的执行计划:
第1步:查找SQL在计划缓存中的信息
sql
-- 查找特定SQL(替换your_keyword为你的SQL关键词)
SELECT
sql_id,
plan_id,
query_sql,
hits,
elapsed_time,
execute_time
FROM GV$OB_PLAN_CACHE_PLAN_STAT
WHERE query_sql LIKE '%your_keyword%'
LIMIT 10;
第2步:查看实际执行计划
sql
-- 使用上一步找到的plan_id(例如123456)
SELECT
operator,
name,
rows,
cost,
property
FROM GV$OB_PLAN_CACHE_PLAN_EXPLAIN
WHERE plan_id = 123456
ORDER BY line_id;
四、实操示例:完整诊断流程
假设我们发现这条SQL执行很慢:
sql
SELECT * FROM orders WHERE customer_id = 100 AND order_date > '2024-01-01';
诊断步骤:
sql
-- 1. 查看执行计划
EXPLAIN EXTENDED
SELECT * FROM orders
WHERE customer_id = 100 AND order_date > '2024-01-01';
-- 2. 如果看到 TABLE SCAN,检查索引
SHOW INDEX FROM orders;
-- 3. 发现没有 customer_id 上的索引,创建索引
CREATE INDEX idx_customer_id ON orders(customer_id, order_date);
-- 4. 再次查看执行计划,确认是否走索引
EXPLAIN EXTENDED
SELECT * FROM orders
WHERE customer_id = 100 AND order_date > '2024-01-01';
-- 现在应该看到 INDEX SCAN 和 idx_customer_id
-- 5. 如果优化器仍然不走索引,可以强制使用(不推荐常规使用)
SELECT /*+ INDEX(orders idx_customer_id) */ *
FROM orders
WHERE customer_id = 100 AND order_date > '2024-01-01';
五、快速判断技巧总结
| 现象 | 判断 | 下一步动作 |
|---|---|---|
OPERATOR = TABLE SCAN |
没走索引 | 检查是否有合适索引,统计信息是否准确 |
OPERATOR = INDEX SCAN |
走了索引 | 检查索引是否高效(回表代价等) |
OPERATOR = TABLE GET |
通过主键访问 | 通常是最高效的访问方式 |
预估行数(EST.ROWS)与实际差异大 |
统计信息可能不准 | 执行ANALYZE TABLE更新统计信息 |
| 有多个可选索引但选错 | 索引选择问题 | 使用Hint指定索引或调整索引设计 |
六、自动化检查脚本
你可以创建一个简单的存储过程来批量检查关键SQL是否走索引:
sql
DELIMITER //
CREATE PROCEDURE check_sql_index_usage()
BEGIN
-- 创建临时表存储结果
CREATE TEMPORARY TABLE IF NOT EXISTS index_check_result (
sql_text TEXT,
uses_index BOOLEAN,
operator_type VARCHAR(50),
index_name VARCHAR(100),
check_time DATETIME
);
-- 这里可以添加你需要检查的SQL
INSERT INTO index_check_result
SELECT
'SELECT * FROM users WHERE user_id = 1001' as sql_text,
CASE WHEN EXISTS (
SELECT 1 FROM (EXPLAIN FORMAT=JSON SELECT * FROM users WHERE user_id = 1001) t
WHERE t.EXPLAIN LIKE '%INDEX_SCAN%' OR t.EXPLAIN LIKE '%TABLE_GET%'
) THEN TRUE ELSE FALSE END as uses_index,
'待检查' as operator_type,
'待检查' as index_name,
NOW() as check_time;
-- 显示结果
SELECT * FROM index_check_result;
DROP TEMPORARY TABLE index_check_result;
END //
DELIMITER ;
-- 执行检查
CALL check_sql_index_usage();
通过以上步骤,你可以系统性地诊断OceanBase中SQL的索引使用情况。关键在于先看执行计划,再分析原因,最后针对性优化。