like '%文字%'性能很差,特别在多个表JOIN后。同样数据和表在SQL Server和MySQL都正常

【 使用环境 】测试环境
【 OB 】OceanBase
【 使用版本 】5.7.25-OceanBase_CE-v4.0.0.0社区版
【问题描述】like '%文字%'性能很差,特别在多个表JOIN后。同样数据和表在SQL Server和MySQL都正常
【复现路径】附件中有表结构(字段太多可只保留用作条件的关键字段),采用以下语句查询时,需时9秒+,同样数据和表在SQL Server和MySQL都只要0.几秒。
各表数据量:
R_TenantAssociation.sql数据量355条。
T_Drivers.sql数据量987条。
T_Vehicle.sql数据量59174条。
R_VehDriver.sql数据量252条。
执行的SQL如下:
select D_Id ,A. TenantId , D_DriverCode , D_Name, D_Sex , D_Birthday , D_IdCard , D_BusinessLicense , D_PhotoName , D_Photo , D_National
, D_Phone , D_Address , D_CulturalDegree , D_QualificationsType , D_QualificationsNumber, D_QNFirstGetTime , D_QNLicenseIssuingTime
, D_QNEffectiveTime , D_QNLicenseIssuingOrgan, D_QNEffective , D_ServiceQualityLevel , D_ServiceQualityTime , D_ServiceQualityOrganName
, D_DrivingLicense , D_DrivingLicenseVehType , D_DrivingLicenseGetTime , D_RoadTransportNumber , D_Logout , D_LogoutDate , D_LogoutCause
, D_CompanyID , D_Credit , D_StarLevel, D_EntryTime , D_RecordTime , D_DriverCardNo , D_CustomerCompanyId , D_DriverStatus, D_ZeroDate
, D_GoToWorkTime , D_OffDutyTime , D_MaritalStatus , D_DrivingLicenseStartDate, D_DrivingLicenseEndDate , D_ForeignAbility , D_JobType
, D_WechatQRCode , D_AlipayQRCode,C.V_No
from T_Drivers A Left Join R_VehDriver B On D_Id=VD_DID Left Join T_Vehicle C On VD_VID=V_Id And C.Tenantid = A.TenantId
where (A.TenantId = 10 OR A.TenantId IN (Select TA_TenId From R_TenantAssociation Where TA_VirtualId=1))

And (D_Name like ‘%文%’ Or D_IdCard like ‘%文%’ Or D_Phone like ‘%文%’ OR V_No like ‘%文%’ )
order by D_Name
【问题现象及影响】
查询需时9秒+,甚至超过10秒导致超时。同样数据和表在SQL Server和MySQL都只要0.几秒。explain查询执行计划发现比Mysql多好多步骤。请定位问题并优化,谢谢。
【附件】
test_slow_statement.rar (5.9 KB)

1 个赞

hello, 能用zip格式上传相关资料么,需要附上相关schema, explain extended计划(需要先收集好统计信息),另外你的租户配置情况怎么样

1 个赞

%文本%进行匹配都走不上索引,如果其他字段没有索引,就直接全表扫了。

可以把具体的执行计划贴一下,看看是不是全表扫

1 个赞

以下三图为OceanBase, SQL Server,MySQL同样结构、数据的执行时间截图。
image
449a677181129c6dbf5ef2e12485d291

以下是表索引,分别是OceanBase和SQL Server的(工具直接迁移的,索引应该是一样的):
2878efb2dc460059e7d56f4804932e76
8308565a9a72fb8a0ab042ffc34027bd

以下是执行计划,分别是OceanBase和MySQL的:


1 个赞

已重新压缩为zip。
第一个附件为表结构和语句。
第二个附件为执行时间、索引、执行计划截图。

test_slow_statement.zip (6.3 KB)
slow_exec_explain_picture.zip (145.2 KB)

公司测试服务器上,用obd demo建的,租户估计就是默认那个。然后自己迁移表和数据过来测试。

old demo的租户资源很小的,这个是用来快速启动,不是用来测试的

另外计划做了 or expansion, 用explain extended_noaddr去打计划,不要用普通的 explain,然后你会看到下面有使用了什么outline, 用outline去控制下计划,把or expansion改写去掉

把租户资源调大, sql里加入并行的hint

explain extended_noaddr去打计划后出现这些,没看懂。
另外同样的语句用在SQL Server和MySQL上很正常。是不是上面说的租户的原因?
explain_noaddr.txt (33.3 KB)

怎么调大这个demo的租户?

怎么调大租户资源?加入并行hint缩到2秒左右,但比起SQL Server和MySql的0.几秒还是很大差距

应该不是租户原因,而是优化器改写过,导致执行计划与Mysql 不一致,使用Hint把执行计划调成与Mysql一致再比较下性能

请教如何调整?

可能和租户有关,只有1 CPU。但是应该和执行计划也有关系,因为用了并行hint后,只缩少到2秒左右,但SQL Server和MySQL都是0.几秒
±------------±---------------±--------±--------+
| tenant_name | unit_server | max_cpu | min_cpu |
±------------±---------------±--------±--------+
| sys | 127.0.0.1:2882 | 1 | 1 |
±------------±---------------±--------±--------+

只有一个sys租户,CPU只有1个,是调大这个,还是另建一个?
应该和租户有一定关系,但是和执行计划也有关系,因为用了并行hint后,只缩少到2秒左右,但SQL Server和MySQL都是0.几秒
±------------±---------------±--------±--------+
| tenant_name | unit_server | max_cpu | min_cpu |
±------------±---------------±--------±--------+
| sys | 127.0.0.1:2882 | 1 | 1 |
±------------±---------------±--------±--------+

这个txt内容有问题吖,你平时不是explain select xxx打计划么
你可以用
explain extended_noaddr select xxx

explain outline select xxx
下面两种可以看到更详细的计划信息

自己搭一个吧。obd demo就是最小规格的单机集群,集群没资源去分配其他租户,你既然和mysql对比,最好就是弄个大点的集群,然后根据你mysql的集群资源,分配一个相同资源的租户 ,对于oceanbase这种多租户架构,是以租户为单位的,不是像mysql起一个节点为单位

explain_outline.txt (4.0 KB)

不是有这两行么

USE_CONCAT(@"SEL$1" 'A.TenantId = ? OR A.TenantId = ANY(SQ(SEL$2))')
USE_CONCAT(@"SEL$CCB1A2BA_2" '(T_OP_OR, (T_OP_LIKE, A.D_Name, ?, ?), (T_OP_LIKE, A.D_IdCard, ?, ?), (T_OP_LIKE, A.D_Phone, ?, ?), (T_OP_LIKE, C.V_No, ?, ?))')

假设你现在写了一个sql: “select c1 from t1”, 你没指定任何outline, 但在这个执行过程中可能发生了什么优化,就会有一些outline信息, 反过来我们可以用outline信息来控制计划

你先执行下你的SQL, 然后查下plan_cache_plan_stat, 类似下面这种,记得把like的关键词换成你sql中的关键词

select * from oceanbase.gv$ob_plan_cache_plan_stat where query_sql like "%DELETE%" \G

然后你会查出一串outline文本对应你刚才txt附上来的outline信息( 以后信息可以给全点,没必要专门截断发这么一段吧,把计划发上面来方便排查吖), 类似下面

把这串文本放到你的SQL中, 比如

select /+BEGIN_OUTLINE_DATA FULL(@“SEL$5C40C8D3” “oceanbase”."__all_virtual_plan_stat"@“SEL$2”) use_concat(xxxx) OPTIMIZER_FEATURES_ENABLE(‘4.0.0.0’) END_OUTLINE_DATA/ c1 from t1;

记得一定不要动前面的data header, 对你来说,你只需要把这段文本中,比如

USE_CONCAT(@"SEL$1" 'A.TenantId = ? OR A.TenantId = ANY(SQ(SEL$2))')

改成

NO_USE_CONCAT(@"SEL$1" 'A.TenantId = ? OR A.TenantId = ANY(SQ(SEL$2))')

然后执行带这串outline的sql,再把explain extended_noaddr的计划发下

1 个赞