本文介绍了使用Hybrid Plan加速宽表查询的技术原理、适用场景、使用限制以及性能测试等内容。
技术原理

在查询大宽表时,若对少数列通过WHERE或JOIN条件进行过滤,或查询TOP K,最后输出筛选出来的行的所有详细信息。对于这类查询,使用列存索引进行查询的效果较好。但在使用列存索引查询筛选出的列的详细信息时,project需要获取所有的列信息,列存索引在获取所有的列信息时存在读放大问题。这种情况下,通过行式索引来查询详细信息效果较好。这种在同一条查询语句中既使用了列式索引,又使用了行式索引的查询方式称之为Hybrid Plan。
Hybrid Plan会加快宽表查询速度,对于执行计划中适合列式索引的部分,会通过列存索引来执行并获取中间结果,中间结果中仅包含主键信息。最后再通过主键结合InnoDB主索引来查询project中所有的列信息并输出。原理如上图所示。
适用场景
宽表查询,且查询结果中会输出多列(15列以上)的场景。
前提条件
集群的产品版本需为企业版,集群版本需为PolarDB MySQL版8.0.1版本且修订版本为8.0.1.1.37及以上。
使用限制
- 查询语句中需要输出的列涉及的表中需要有显式定义的主键。 
- 暂不支持对分区表使用Hybrid Plan加速宽表查询功能。 
如果慢SQL中需要使用Hybrid Plan加速宽表查询功能,但受限于表类型等因素,您可以联系我们寻求帮助。
参数说明
您需要在数据库中将imci_enable_hybrid_plan参数的值设置为ON来开启Hybrid Plan加速宽表查询功能,开启后优化器会选择合适的查询语句使用Hybrid Plan加速宽表查询。如果需要强制某个查询语句使用Hybrid Plan加速,您可以在查询语句中的HINT语法中将参数imci_optimizer_switch中的force_hybrid_index_search参数的值设置为ON来加速查询。
| 参数名称 | 参数说明 | 
| imci_enable_hybrid_plan | Hybrid Plan加速宽表查询功能的控制开关。取值范围如下: 
 | 
| imci_optimizer_switch | 是否在满足条件的查询语句中使用Hybrid Plan加速宽表查询。取值范围如下: 
 | 
使用说明
此处以SELECT * FROM t1;为例来介绍如何使用Hybrid Plan加速宽表查询功能。操作步骤如下:
- 连接PolarDB数据库。具体操作步骤请参见连接数据库集群。 
- 将参数 - imci_enable_hybrid_plan的值设置为ON,来开启Hybrid Plan加速宽表查询功能。开启后优化器会选择合适的查询语句使用Hybrid Plan加速宽表查询。- SET imci_enable_hybrid_plan=ON;
- 如果需要强制某个查询语句使用Hybrid Plan加速,您可以在需要使用Hybrid Plan加速宽表查询功能的SQL语句中添加HINT语法,并在HINT语法中将参数 - imci_optimizer_switch中的- force_hybrid_index_search参数的值设置为ON。- SELECT /*+ SET_VAR(imci_optimizer_switch='force_hybrid_index_search=ON') */ * FROM t1;- 您可以通过EXPLAIN语句来判断在SQL语句中使用的Hybrid Plan加速宽表查询功能是否生效。如果执行计划中包含HybridIndexSearch,则表示Hybrid Plan加速宽表查询功能生效。 - EXPLAIN SELECT /*+ SET_VAR(imci_optimizer_switch='force_hybrid_index_search=ON') */ * FROM t1;- 查询结果如下: - +----+-------------------------+------+---------------------------------------------------------------+ | ID | Operator | Name | Extra Info | +----+-------------------------+------+---------------------------------------------------------------+ | 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = unlimited) | | 2 | └─HybridIndexSearch | | Used table: t1 | | 3 | └─Compute Scalar | | | | 4 | └─Table Scan | t1 | | +----+-------------------------+------+---------------------------------------------------------------+ 4 rows in set (0.02 sec)
性能测试
此处以ClickHouse官方提供的OnTime数据集为基础,来测试在SQL语句中仅使用行存索引、仅使用列存索引以及使用Hybrid Plan加速宽表查询三种场景下的查询效果。
OnTime数据集中的表包含109列,是一个典型的大宽表。在该测试中修改了ClickHouse的表定义,并为这张表显式定义了主键。修改后的表结构如下所示:
CREATE TABLE `ontime` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Year` year(4) DEFAULT NULL,
  `Quarter` tinyint(4) DEFAULT NULL,
  `Month` tinyint(4) DEFAULT NULL,
  `DayofMonth` tinyint(4) DEFAULT NULL,
  `DayOfWeek` tinyint(4) DEFAULT NULL,
  `FlightDate` date DEFAULT NULL,
  `UniqueCarrier` char(7) DEFAULT NULL,
  `AirlineID` int(11) DEFAULT NULL,
  `Carrier` char(2) DEFAULT NULL,
  `TailNum` varchar(50) DEFAULT NULL,
  `FlightNum` varchar(10) DEFAULT NULL,
  `OriginAirportID` int(11) DEFAULT NULL,
  `OriginAirportSeqID` int(11) DEFAULT NULL,
  `OriginCityMarketID` int(11) DEFAULT NULL,
  `Origin` char(5) DEFAULT NULL,
  `OriginCityName` varchar(100) DEFAULT NULL,
  `OriginState` char(2) DEFAULT NULL,
  `OriginStateFips` varchar(10) DEFAULT NULL,
  `OriginStateName` varchar(100) DEFAULT NULL,
  `OriginWac` int(11) DEFAULT NULL,
  `DestAirportID` int(11) DEFAULT NULL,
  `DestAirportSeqID` int(11) DEFAULT NULL,
  `DestCityMarketID` int(11) DEFAULT NULL,
  `Dest` char(5) DEFAULT NULL,
  `DestCityName` varchar(100) DEFAULT NULL,
  `DestState` char(2) DEFAULT NULL,
  `DestStateFips` varchar(10) DEFAULT NULL,
  `DestStateName` varchar(100) DEFAULT NULL,
  `DestWac` int(11) DEFAULT NULL,
  `CRSDepTime` int(11) DEFAULT NULL,
  `DepTime` int(11) DEFAULT NULL,
  `DepDelay` int(11) DEFAULT NULL,
  `DepDelayMinutes` int(11) DEFAULT NULL,
  `DepDel15` int(11) DEFAULT NULL,
  `DepartureDelayGroups` int(11) DEFAULT NULL,
  `DepTimeBlk` varchar(20) DEFAULT NULL,
  `TaxiOut` int(11) DEFAULT NULL,
  `WheelsOff` int(11) DEFAULT NULL,
  `WheelsOn` int(11) DEFAULT NULL,
  `TaxiIn` int(11) DEFAULT NULL,
  `CRSArrTime` int(11) DEFAULT NULL,
  `ArrTime` int(11) DEFAULT NULL,
  `ArrDelay` int(11) DEFAULT NULL,
  `ArrDelayMinutes` int(11) DEFAULT NULL,
  `ArrDel15` int(11) DEFAULT NULL,
  `ArrivalDelayGroups` int(11) DEFAULT NULL,
  `ArrTimeBlk` varchar(20) DEFAULT NULL,
  `Cancelled` tinyint(4) DEFAULT NULL,
  `CancellationCode` char(1) DEFAULT NULL,
  `Diverted` tinyint(4) DEFAULT NULL,
  `CRSElapsedTime` int(11) DEFAULT NULL,
  `ActualElapsedTime` int(11) DEFAULT NULL,
  `AirTime` int(11) DEFAULT NULL,
  `Flights` int(11) DEFAULT NULL,
  `Distance` int(11) DEFAULT NULL,
  `DistanceGroup` tinyint(4) DEFAULT NULL,
  `CarrierDelay` int(11) DEFAULT NULL,
  `WeatherDelay` int(11) DEFAULT NULL,
  `NASDelay` int(11) DEFAULT NULL,
  `SecurityDelay` int(11) DEFAULT NULL,
  `LateAircraftDelay` int(11) DEFAULT NULL,
  `FirstDepTime` varchar(10) DEFAULT NULL,
  `TotalAddGTime` varchar(10) DEFAULT NULL,
  `LongestAddGTime` varchar(10) DEFAULT NULL,
  `DivAirportLandings` varchar(10) DEFAULT NULL,
  `DivReachedDest` varchar(10) DEFAULT NULL,
  `DivActualElapsedTime` varchar(10) DEFAULT NULL,
  `DivArrDelay` varchar(10) DEFAULT NULL,
  `DivDistance` varchar(10) DEFAULT NULL,
  `Div1Airport` varchar(10) DEFAULT NULL,
  `Div1AirportID` int(11) DEFAULT NULL,
  `Div1AirportSeqID` int(11) DEFAULT NULL,
  `Div1WheelsOn` varchar(10) DEFAULT NULL,
  `Div1TotalGTime` varchar(10) DEFAULT NULL,
  `Div1LongestGTime` varchar(10) DEFAULT NULL,
  `Div1WheelsOff` varchar(10) DEFAULT NULL,
  `Div1TailNum` varchar(10) DEFAULT NULL,
  `Div2Airport` varchar(10) DEFAULT NULL,
  `Div2AirportID` int(11) DEFAULT NULL,
  `Div2AirportSeqID` int(11) DEFAULT NULL,
  `Div2WheelsOn` varchar(10) DEFAULT NULL,
  `Div2TotalGTime` varchar(10) DEFAULT NULL,
  `Div2LongestGTime` varchar(10) DEFAULT NULL,
  `Div2WheelsOff` varchar(10) DEFAULT NULL,
  `Div2TailNum` varchar(10) DEFAULT NULL,
  `Div3Airport` varchar(10) DEFAULT NULL,
  `Div3AirportID` int(11) DEFAULT NULL,
  `Div3AirportSeqID` int(11) DEFAULT NULL,
  `Div3WheelsOn` varchar(10) DEFAULT NULL,
  `Div3TotalGTime` varchar(10) DEFAULT NULL,
  `Div3LongestGTime` varchar(10) DEFAULT NULL,
  `Div3WheelsOff` varchar(10) DEFAULT NULL,
  `Div3TailNum` varchar(10) DEFAULT NULL,
  `Div4Airport` varchar(10) DEFAULT NULL,
  `Div4AirportID` int(11) DEFAULT NULL,
  `Div4AirportSeqID` int(11) DEFAULT NULL,
  `Div4WheelsOn` varchar(10) DEFAULT NULL,
  `Div4TotalGTime` varchar(10) DEFAULT NULL,
  `Div4LongestGTime` varchar(10) DEFAULT NULL,
  `Div4WheelsOff` varchar(10) DEFAULT NULL,
  `Div4TailNum` varchar(10) DEFAULT NULL,
  `Div5Airport` varchar(10) DEFAULT NULL,
  `Div5AirportID` int(11) DEFAULT NULL,
  `Div5AirportSeqID` int(11) DEFAULT NULL,
  `Div5WheelsOn` varchar(10) DEFAULT NULL,
  `Div5TotalGTime` varchar(10) DEFAULT NULL,
  `Div5LongestGTime` varchar(10) DEFAULT NULL,
  `Div5WheelsOff` varchar(10) DEFAULT NULL,
  `Div5TailNum` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=58592318 DEFAULT CHARSET=latin1 COMMENT='columnar=1'该测试使用的SQL语句如下:
SELECT * FROM ontime ORDER BY ArrTime LIMIT 1000;分别在仅使用行存索引、仅使用列存索引以及使用Hybrid Plan加速宽表查询三种场景下执行该SQL语句。三种场景下的执行计划均为冷启动查询,查询时间如下:
| 仅使用行存 | 仅使用列存索引 | 使用Hybrid Plan加速列存宽表查询 | 
| 232.48秒 | 2.56秒 | 0.33秒 | 
由上表中的查询时间可以看出,对于涉及宽表的查询,使用Hybrid Plan加速宽表查询功能可以获得明显的性能提升效果。