INDEX SKIP SCAN 和 INDEX RANGE SCAN

本文详细解析了Oracle数据库中的两种索引扫描方式:索引跳跃式扫描(Index Skip Scan)和索引范围扫描(Index Range Scan)。介绍了这两种扫描方式的工作原理、适用场景以及如何通过它们提高查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表有一个复合索引,而在查询中有除了索引中第一列的其他列作为条件,并且优化器模式为CBO,这时候查询计划就有可能使用到SS
       Skip scan会探测出索引前导列的唯一值个数,每个唯一值都会作为常规扫描的入口,在此基础上做一次查找,最后合并这些查询
       例如:表employees (sex, employee_id, address) ,有一个组合索引(sex, employee_id). 
       在索引跳跃的情况下,我们可以逻辑上把他们看成两个索引:
       一个是(男,employee_id),一个是(女,employee_id).
       select * from employees where employee_id=1;
       发出这个查询后,oracle先进入sex为男的入口,查找employee_id=1的条目。再进入sex为女的入口,查找employee_id=1的条目。最后合并两个结果集
       ORACLE官方说,在前导列唯一值较少的情况下,才会用到index skip can。这个其实好理解,就是入口要少,这也是skip scan的条件
       ORACLE也承认skip scan没有直接索引查询快,但可以这样说,相比于整个表扫描(table scan),索引跳跃式扫描的速度要快得多
       在Oracle9i版本之前,当SQL查询中包含sex和employee_id时,或者查询指定sex的时候才可以使用这一索引,下面的查询就不能使用索引:
       select employee_id from employees where employee_id=7788;
       Oracle9i的索引跳跃式扫描执行规则允许使用连接索引,即使SQL查询中不指定性别
       这一特性使得无需在employee_id行中提供第二个索引
       索引跳跃式扫描适用于硬盘空间和存储空间相当紧缺的情况
       因为一个索引可以满足两个查询条件的使用,比单独建两个索引自然节约了空间

       例如:

[sql]  view plain  copy
  1. hr@ORCL> desc t  
  2.  Name                                                  Null?    Type  
  3.  ----------------------------------------------------- -------- ------------------------------------  
  4.  EMPNO                                                 NOT NULL NUMBER  
  5.  SEX                                                   NOT NULL VARCHAR2(4)  
  6.  ENAME                                                          VARCHAR2(4)  
  7.   
  8. hr@ORCL> create index sex_empno on t (sex,empno);  
  9.   
  10. Index created.  
  11.   
  12. hr@ORCL> analyze index sex_empno compute statistics;  
  13.   
  14. Index analyzed.  
  15.   
  16. hr@ORCL> select /*+ index_ss(t) */ empno from t where empno=8;  
  17.   
  18. Execution Plan  
  19. ----------------------------------------------------------  
  20. Plan hash value: 3008009344  
  21.   
  22. ------------------------------------------------------------------------------  
  23. | Id  | Operation        | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
  24. ------------------------------------------------------------------------------  
  25. |   0 | SELECT STATEMENT |           |     1 |    10 |     3   (0)| 00:00:01 |  
  26. |*  1 |  INDEX SKIP SCAN | SEX_EMPNO |     1 |    10 |     3   (0)| 00:00:01 |  
  27. ------------------------------------------------------------------------------  


       先看个图:

     

       假如我现在要查找employee_id是109的记录,从图可以看出来,109的记录存在与块3和块5上
       但是skip scan是通过什么样的方式定位到这两个块呢?
       ORACLE可以在SKIP SCAN中,选择相应的入口后,通过根节点和分支节点的信息,非常精准的定位到记录的叶子块,即块3和块5.
       如果要查找employee_id为109的条目,ORACLE进入到入口M后,直接就可以定位到块3.而不需要扫描块1和块2.
       进入到入口F后,直接就可以定位到块5,而不需要扫描块4和块6
       那么,我们上面这条查询,经过skip scan后,内部可能是:
       select empno from t where sex='M' and empno=8
       union
       select empno from t where sex='F' and empno=8;
       我们可以想象,如果索引前导列的唯一值很多,那么势必会大大削弱skip scan的效能,因为可能存在很多union
       有时候为了避免index skip scan,建立新的索引是有必要的
       
       ㈡ INDEX Range Scan
       
          INDEX Range SCAN是一种很常见的表访问方式
          在INDEX Range SCAN中,Oracle访问毗邻的索引条目,然后根据索引里面的rowid去检索表的记录
          例如:查询范围为80号部门里的所有员工

[sql]  view plain  copy
  1. hr@ORCL> select JOB_ID,FIRST_NAME from employees where DEPARTMENT_ID=80;  
  2.   
  3. Execution Plan  
  4. ----------------------------------------------------------  
  5. Plan hash value: 2056577954  
  6.   
  7. -------------------------------------------------------------------------------------------------  
  8. | Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time     |  
  9. -------------------------------------------------------------------------------------------------  
  10. |   0 | SELECT STATEMENT            |                   |    34 |   646 |     4   (0)| 00:00:01 |  
  11. |   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |    34 |   646 |     4   (0)| 00:00:01 |  
  12. |*  2 |   INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |    34 |       |     1   (0)| 00:00:01 |  
  13. -------------------------------------------------------------------------------------------------  

          INDEX RANGE SCAN是范围扫描,举个例子,有1到100,分5个范围,要查询45就要到第3的范围里查,这样会很快
          Index Unique Scan和Index Range Scan在B Tree上的搜索路径是一样的
          只是Index Unique Scan在找到应该含有要找的Index Key的block后便停止了搜索,因为该键是唯一的
          而Index Range Scan还要循着指针继续找下去直到条件不满足时
          并且,Index Range Scan只是索引上的查询,与是否扫描表没有关系
          如果所选择的列都在index上就不用去scan table
          如果扫描到表, 必然还有一个table access by rowid,正如上例所展示的
          
          通过index range scan访问的表可以通过按照索引顺序重新建立表来提高效率
          原因有二:
          ①  如果你只读一部分数据,假设20% ,如果表数据顺序混乱,实际上可能把整个表都读进来了
               如果表顺序和索引一致,则只需要读进 20%的表的block就够了。这是简单情况
          ② 复杂情况下,顺序混乱的时候 block  可能在整个查询的不同时间点多次反复访问
               当再次要访问这个块的时候说不定已经被换出去了,或者被修改过了,那代价更大
               而如果顺序一样,对同一个block的访问集中在一段连续的很短的时间内,变数少,不会对同一个block产生多次IO
<think>好的,我现在需要帮助用户解决FastLIO算法中出现的“no point skip this scan”的问题。首先,我应该了解FastLIO的基本原理常见问题。FastLIO是一个高效的激光雷达惯性里程计算法,主要用于SLAM(同步定位与地图构建)。用户提到的错误信息“no point skip this scan”可能是在处理点云数据时出现的,可能的原因包括点云数据无效、传感器输入问题或算法配置错误。 接下来,我需要回忆一下FastLIO的工作流程。FastLIO通常通过IMU数据激光雷达点云进行融合,实现位姿估计。如果在某次扫描中没有有效的点云数据,算法可能会跳过该次扫描,并输出这样的错误信息。可能的原因可能有以下几点: 1. **传感器数据问题**:激光雷达没有正确输入数据,或者数据格式不符合预期。例如,点云数据为空,或者时间戳同步出现问题,导致算法无法处理当前帧。 2. **预处理配置错误**:可能设置了过滤条件(如距离范围或强度阈值),导致过滤后的点云为空。例如,配置文件中可能设置了过大的最小距离或过高的强度阈值,过滤掉了所有点。 3. **运动过快或环境问题**:如果载体移动过快,可能导致点云过于稀疏,或者在特定环境下(如透明或高反射表面),激光雷达无法捕捉到有效点云。 4. **算法逻辑中的检查机制**:FastLIO可能在代码中有检查点云是否为空的逻辑,如果检测到空点云,就会触发该警告,并跳过当前扫描。 接下来,我需要考虑如何逐步排查这些问题。用户可能需要检查数据输入是否正确,查看是否有点云数据被正确接收。然后检查配置文件中的预处理参数,确保过滤条件合理。此外,检查硬件连接传感器是否正常工作,确保没有硬件故障。如果环境导致点云稀疏,可能需要调整算法参数或添加其他传感器辅助。 另外,参考用户提供的引用内容,虽然主要关于B+树日志文件,但可以联想到数据处理的效率问题。FastLIO在处理点云时可能需要高效的数据结构,如果点云处理出现延迟或丢帧,也可能导致类似问题。但具体到“no point skip this scan”,更多还是数据本身的问题。 可能的解决方案包括: - 检查激光雷达的数据流,确保点云被正确接收。 - 调整预处理参数,如减小`blind`区域的设置或调整强度过滤阈值。 - 检查时间同步问题,确保IMU激光雷达数据的时间戳对齐。 - 在代码中增加调试输出,查看点云处理前后的数量变化,确认过滤步骤是否导致数据丢失。 用户可能需要具体的步骤指导,比如如何修改配置文件中的参数,如何检查数据输入等。此外,如果问题出现在特定环境下,可能需要建议使用其他传感器融合或调整算法参数以适应环境变化。 最后,生成的相关问题需要围绕FastLIO的配置、数据输入、性能优化与其他算法的比较,帮助用户深入理解可能的相关问题。</think>关于FastLIO算法中出现的'no point skip this scan'问题,该提示通常表示当前激光雷达扫描帧未包含有效点云数据。以下是分步排查方案: ### 一、数据源验证 1. **检查传感器输出** - 使用`rostopic echo /livox_cloud`(ROS环境)确认激光雷达数据流是否正常 - 验证点云消息的`header.stamp`时间戳连续性,异常时间间隔会导致数据丢弃[^1] - 示例诊断命令: ```bash rostopic hz /livox_cloud # 检查数据频率 rostopic bw /livox_cloud # 检查带宽 ``` 2. **数据格式校验** - 确认使用`livox_ros_driver`时选择正确的点云格式: ```yaml # launch文件配置示例 publish_freq: 10.0 # 采样频率 pointcloud_format: 0 # 0-原始格式,1-自定义格式 ``` ### 二、预处理参数调优 1. **调整盲区过滤参数** 在`config/xxx.yaml`中修改: ```yaml preprocess: blind: 0.5 # 最小有效距离(单位:米),建议从0.3开始测试 max_range: 100.0 # 最大探测距离 ``` 过大的`blind`值会过滤近距离墙面反射点 2. **强度阈值配置** ```yaml feature_extract: intensity_thr: 0.1 # 点云强度阈值,针对不同环境调整 ``` 可通过可视化工具检查强度分布: ```bash rviz -d src/FAST_LIO/launch/rviz.rviz ``` ### 三、运动状态分析 1. **检查IMU同步状态** - 使用`imu_tk`工具校准IMU-Camera外参 - 验证时间同步误差应小于激光雷达采样周期($ \Delta t < 1/f_{lidar} $) 2. **动态特性测试** - 在静态环境下测试排除运动干扰 - 计算运动速度$ v = \sqrt{\omega_x^2 + \omega_y^2 + \omega_z^2} $,建议初始测试保持$ v < 2m/s $ ### 四、代码层调试 1. **添加调试输出** 在`Preprocess::process`函数中添加: ```cpp cout << "原始点数:" << pl_orig.points.size() << " 过滤后点数:" << pl_surf.points.size() << endl; ``` 观察各阶段数据衰减情况 2. **修改点云有效性检查** 注释掉`fast_lio.cpp`中的扫描跳过逻辑: ```cpp // if(plsize == 0) { // cout << "no point skip this scan" << endl; // return; // } ``` (仅用于测试,正式运行需还原) ### 五、硬件环境优化 1. **安装角度调整** - 保证激光雷达与水平面夹角$ \theta \in [15^\circ, 30^\circ] $ - 使用倾角仪测量安装姿态,满足$ \tan\theta = h/D $(h为安装高度,D为有效探测距离) 2. **反射特性增强** - 在低反射率环境(如黑色物体)添加标记点 - 测试环境建议满足反射率$ \rho > 0.4 $
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值