常见问题

在使用Lindorm SQL查询宽表数据或创建索引时,可能会遇到报错或出现查询性能不符合预期的情况。本文介绍Lindorm SQL使用时的常见问题和解决方案。

说明

本文列举的常见问题仅适用于宽表引擎

如何解决或规避低效查询问题?

什么是低效查询?低效查询有哪些特点?

如果查询语句中带有过滤条件,但该过滤条件无法有效地利用已有的主键或索引,导致查询时必须扫描全表,这样的查询被视为低效查询。

如果执行查询语句后,宽表引擎报错This query may be a full table scan and thus may have unpredictable performance,表示该查询是低效查询。假设test表的联合主键由p1,p2,p3三个列组成,p1列是主键的第一列,查询条件为SELECT * FROM test WHERE p2=10;。此时查询条件中未包含第一个主键列p1,因此该查询语句会被认定为低效查询语句。

重要

由于低效查询可能会带来性能稳定性风险,默认情况下Lindorm会检测并阻止低效查询的执行。

查询条件WHERE中的列是主键列或索引列,为什么查询还是触发了低效查询异常?

宽表引擎的主键、二级索引和MySQL联合索引的匹配规则类似,均遵循最左匹配原则,即在多个列组成的联合主键或索引中,系统从主键或索引键的第一列(最左侧列)开始逐一与查询条件中的列进行匹配。如果查询条件中不包含主键或索引键的第一列,则此时查询仍不会命中主键或二级索引,导致查询仍然是低效查询。

假设test表的主键由p1、p2、p3三个列组成,p1列是主键的第一列,根据最左匹配原则,查询数据时系统将从p1列开始匹配。如果查询条件中未包含p1列,例如SELECT * FROM test WHERE p2<30;,此时无法匹配到主键第一列p1,系统不会命中主键进而查询全表数据以满足查询条件p2<30

如何规避低效查询?

以下是业务中规避低效查询的一些推荐的方法:

  • 优化查询条件,在WHERE语句中增加表的主键,或保证查询条件中的列满足最左匹配原则。

  • 修改表的主键设计,避免大查询。详细介绍,请参见如何设计宽表主键

  • 为表创建二级索引。详细介绍,请参见二级索引

  • 如果表的多个列均存在多维检索需求,可以给表创建多维搜索索引加速查询。详细介绍,请参见搜索索引

  • 在查询语句中增加查询优化的HINT:/*+ _l_allow_filtering_ */,强制宽表引擎执行低效查询。例如SELECT /*+ _l_allow_filtering_ */ * FROM dt WHERE nonPK=100;

    重要

    强制执行低效查询可能会带来性能稳定性风险,请谨慎使用。

使用GROUP BY查询时报错The diff group keys of subPlan is over lindorm.aggregate.subplan.groupby.keys.limit=..., it may cost a lot memory so we shutdown this SubPlan

原因:

GROUP BY操作形成的分组数过多,可能消耗了大量的内存资源,从而加重实例负载,因此宽表引擎限制了结果集中分组数过大的查询。

解决方案:

  • 在查询语句中添加过滤条件,减少最终分组数。

  • 联系Lindorm技术支持(钉钉号:s0s3eg3)调大分组数的阈值。

    重要

    调大分组数的阈值可能会影响实例的稳定性。

  • 针对多维查询匹配场景,建议使用搜索索引。详细介绍,请参见搜索索引介绍

对开启动态列的表执行SELECT *查询报错Limit of this select statement is not set or exceeds config when select all columns from table with property DYNAMIC_COLUMNS=true

原因:

开启动态列的表可能包含大量的动态列,且表的Schema定义不固定。如果对这类表进行全表扫描,将会导致IO消耗严重,加重实例负载。为避免高负载情况的产生,Lindorm宽表引擎对动态列表的查询语句进行了限制。

解决方案:

在SELECT语句中添加LIMIT子句,限制返回结果的数量。例如SELECT * FROM test LIMIT 10;

为什么创建二级索引时报错Executing job number exceed, max job number = 8

原因:

一个实例中仅允许同时存在8个二级索引的构建任务。如果某一时刻二级索引的构建任务数已达8个,则再次创建新的二级索引时,创建语句将会报错。

解决方案:

建议您避免同时创建大量二级索引。如果有大量创建的需求,请联系Lindorm技术支持(钉钉号:s0s3eg3)。

在宽表引擎上已执行删除列操作,为什么重新添加同名列时会报错column is under deleting?

原因:

为避免由于数据类型等因素引发的脏数据问题,在您执行删除列的操作后,宽表引擎还需要异步清理内存、热存储和冷存储上该列的数据。在数据全部清理完之前,系统不允许重新添加同名的新列。

解决方案:

由于数据清理由系统自行完成,可能会消耗很长时间。建议您通过以下方式加速数据的清理过程,待数据清理完成之后重新添加同名列。

假设执行了删除列操作的表名为dt

-- 执行FLUSH操作,强制将内存中残留的数据刷到存储媒介上
ALTER TABLE dt FLUSH;

-- 执行COMPACTION操作,执行数据的合并和删除
ALTER TABLE dt COMPACT;
重要
  • FLUSH语法从SQL引擎2.7.1版本开始支持。如何查看SQL引擎的版本,请参见SQL版本说明

  • FLUSH操作和COMPACT操作是异步操作。语句执行成功并不代表数据清理完成,需要等待一段时间才能彻底清理完成。

  • 对数据量大的表执行COMPACT操作,其执行期间会占用较多系统资源,因此不建议在业务高峰期执行。

创建二级索引后,写入数据时为什么会报错Performing put operations with User-Defined-Timestamp in indexed column on MULTABLE_LATEST table is unsupported

原因:

如果写入时显式指定了自定义时间戳(例如,使用UPSERT语句写入数据时,通过/*+ _l_ts */指定了自定义时间戳),此时要求主表与二级索引表之间的可变性(Mutability)必须是MULTABLE_ALL。但是出于性能考虑,Lindorm系统默认将主表与索引表的可变性配置为MULTABLE_LATEST,在这种配置下创建二级索引并启用会触发可变性约束限制,导致报错。

解决方案:

由于创建索引表后MUTABILITY参数的值不支持修改,因此您需要先删除原有的二级索引。

  1. 删除主表中原有的二级索引。

    -- 禁用原有二级索引
    ALTER INDEX IF EXISTS <原有二级索引名> ON <主表名> DISABLED;
    
    -- 删除原有二级索引
    DROP INDEX IF EXISTS <原有二级索引名> ON <主表名>;

    DROP INDEX语法的详细介绍,请参见删除二级索引

  2. 将主表的MUTABILITY属性的值修改为MUTABLE_ALL

    ALTER TABLE IF EXISTS <主表名> SET MUTABILITY='MUTABLE_ALL';
  3. 创建新的二级索引,并写入数据。创建二级索引的语法说明,请参见CREATE INDEX

    说明