面试:介绍Oracle数据库select语句执行过程?

在这里插入图片描述
以下详细介绍 Oracle 数据库中一条查询语句 SELECT id FROM t1 WHERE name='cjc' 的完整执行过程,涵盖客户端、网络、应用、数据库、内存和磁盘的全路径细节:


一、全路径执行流程概览

客户端应用
网络传输
监听器
服务器进程
SQL解析
执行计划
数据读取
结果返回

二、详细执行步骤解析

1. 客户端应用程序发起请求
  • 应用层处理
    • 应用程序(如Java/Python)调用数据库接口(JDBC/ODBC)
    • 构造SQL语句:SELECT id FROM t1 WHERE name='cjc'
    • 示例代码(Java JDBC):
      Connection conn = DriverManager.getConnection(url, user, pwd);
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT id FROM t1 WHERE name='cjc'"); // 触发请求
      
  • 关键内存操作
    • 应用进程在用户空间创建SQL文本缓冲区
    • 绑定变量处理(若使用预编译语句)
2. 网络传输过程
  • 协议封装
    • JDBC驱动将SQL文本封装成 Oracle Net 协议包
    • 使用 TNS(Transparent Network Substrate)格式:
      | TNS Header | SQL Text | Session ID | 
      
  • 传输路径
    TCP/IP
    IPC/Socket
    客户端
    监听器:1521
    服务器进程
  • 网络细节
    • 默认端口 1521
    • 包大小由 SDU(Session Data Unit)参数控制(默认 8KB)
    • 加密支持(SQLNet.ENCRYPTION)
3. 数据库监听器处理
  • 监听器(LISTENER)
    LSNRCTL> status
    Listening Endpoints Summary...
      (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dbsvr)(PORT=1521)))
    
  • 工作流程
    1. 接收客户端连接请求
    2. 检查 listener.ora 配置
    3. 创建专用服务器进程(Dedicated Server)或分配共享进程
    4. 将连接移交给服务器进程
4. 服务器进程处理(关键阶段)
(1) SQL解析阶段
  • 共享池(Shared Pool)操作
    SELECT * FROM v$sql WHERE sql_text LIKE 'SELECT id FROM t1%';
    
  • 解析步骤
    1. 语法检查:验证SQL结构
    2. 语义检查
      • 检查表 t1 是否存在(访问 obj$ 数据字典)
      • 检查列 id, name 是否存在
      • 权限验证(dba_tab_privs
    3. 哈希计算:生成SQL指纹(sql_id
    4. 软解析/硬解析
      • 若共享池存在缓存:直接复用执行计划(软解析)
      • 若不存在:触发硬解析(消耗CPU)
(2) 优化器生成执行计划
  • 优化器工作
    EXPLAIN PLAN FOR 
    SELECT id FROM t1 WHERE name='cjc';
    
  • 决策过程
    1. 读取统计信息(dba_tables.num_rows, dba_tab_columns.density
    2. 计算访问路径代价:
      • 全表扫描:cost = num_rows * cpu_cost
      • 索引扫描:cost = blevel + leaf_blocks * sel(选择率)
    3. 选择最优计划(假设 name 有索引):
      OPERATION          OPTIONS         OBJECT_NAME
      ------------------ --------------- -----------
      SELECT STATEMENT
      TABLE ACCESS       BY INDEX ROWID  T1
      INDEX              RANGE SCAN      IDX_T1_NAME
      
(3) 执行阶段
  • 内存读取流程
    未命中
    命中
    服务器进程
    PGA
    请求数据块
    磁盘读取
    返回Buffer Cache
  • 详细步骤
    1. 根据索引 IDX_T1_NAME 查找 name='cjc'ROWID
    2. 通过 ROWID 访问表数据块
    3. 数据获取路径:
      • 检查 Buffer Cache 是否缓存数据块
      • 若未命中:发起物理 I/O 读取磁盘文件
    4. 获取 id 列值
5. 磁盘I/O操作
  • 物理读取路径
    SELECT file_id, block_id 
    FROM dba_extents 
    WHERE segment_name = 'T1';
    
  • I/O 过程
    1. 计算数据块地址:ROWID = AAAATE5AAEAAAAFTAAB
      • 文件号:AAAATE5
      • 块号:AAEAAAAF
      • 行号:TAAB
    2. 通过 DBWn 后台进程管理数据文件访问
    3. 磁盘访问顺序:
      • 索引段 → 表段 → UNDO段(若需要一致性读)
    4. 数据块读入 Buffer Cache
6. 结果集返回
  • 返回路径
    TCP/IP
    JDBC
    服务器进程
    客户端
    应用程序
  • 内存操作
    1. 结果集在 PGA 中排序(若需排序)
    2. 分批次传输(受 arraysize 控制)
    3. 网络包封装:
      | TNS Header | Data Row 1 | Data Row 2 | ... |
      
  • 客户端处理
    while (rs.next()) {
      int id = rs.getInt("id"); // 从Socket缓冲区解包数据
    }
    

三、关键内存组件交互

内存区域组件在查询中的作用
SGAShared Pool缓存SQL解析树、执行计划
Buffer Cache缓存表/索引数据块(减少物理I/O)
Library Cache存储SQL文本哈希值
PGASort Area处理ORDER BY等排序操作
Session Memory存储绑定变量、游标状态
OS Page Cache文件系统缓存缓存数据文件(减少真实磁盘I/O)

四、性能关键点与优化

  1. 软/硬解析优化

    -- 查看解析比例
    SELECT name, value FROM v$sysstat 
    WHERE name IN ('parse count (hard)', 'parse count (total)');
    
    • 目标:软解析率 > 90%
    • 方案:使用绑定变量
  2. I/O 优化

    -- 检查缓存命中率
    SELECT 1 - (phy.value / (cur.value + con.value)) "Buffer Hit Ratio"
    FROM v$sysstat cur, v$sysstat con, v$sysstat phy
    WHERE cur.name = 'db block gets from cache'
      AND con.name = 'consistent gets from cache'
      AND phy.name = 'physical reads cache';
    
    • 目标:命中率 > 95%
    • 方案:增加 DB_CACHE_SIZE
  3. 索引优化

    -- 检查索引使用
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('sql_id'));
    
    • 确认是否走索引
    • 避免回表:使用覆盖索引 CREATE INDEX idx_cover ON t1(name, id)

五、故障排查命令大全

  1. SQL执行跟踪

    ALTER SESSION SET sql_trace = true;  -- 开启跟踪
    EXEC DBMS_MONITOR.session_trace_enable;  -- 更精细控制
    tkprof ora_12345.trc output.txt  -- 分析跟踪文件
    
  2. 实时监控等待事件

    SELECT sid, event, wait_time, seconds_in_wait 
    FROM v$session_wait 
    WHERE sql_id = 'gxpun3s4t5g1c';
    
  3. 内存分析

    -- 检查Shared Pool碎片
    SELECT * FROM v$shared_pool_reserved;
    
    -- 检查Buffer Cache内容
    SELECT obj.owner, obj.object_name, bh.blocks 
    FROM v$bh bh, dba_objects obj 
    WHERE bh.objd = obj.object_id;
    
  4. I/O 性能分析

    -- 查看文件级I/O
    SELECT file_name, phyrds, phywrts, readtim, writetim 
    FROM v$filestat NATURAL JOIN dba_data_files;
    

六、典型性能问题案例

场景:查询 WHERE name='cjc' 突然变慢
排查过程

  1. 检查执行计划变化:

    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('sql_id'));
    
    • 发现索引失效 → 统计信息过旧
  2. 分析等待事件:

    SELECT event, total_waits, time_waited_micro
    FROM v$sql_event_info 
    WHERE sql_id = 'gxpun3s4t5g1c';
    
    • 主要等待 db file sequential read(索引I/O)
  3. 解决方案:

    EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA','T1'); -- 重新收集统计信息
    ALTER INDEX idx_t1_name REBUILD; -- 重建索引
    

总结

Oracle SQL查询的核心路径:
客户端请求 → 监听器路由 → 服务器进程解析 → 优化器生成计划 → Buffer Cache交互 → 物理I/O(若未缓存) → 结果集返回。每个环节的瓶颈(硬解析、I/O等待、索引失效)都可通过动态性能视图精准定位。掌握内存结构(SGA/PGA)和磁盘交互机制是性能优化的关键。

欢迎关注我的公众号《IT小Chen

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值