Java-MariaDB在符合Hibernate标准的情况下运行缓慢



环境:

mariadb-java-client-2.7.0

DB:MariaDB 10.5.7

ojdbc8-Oracle 11.2.0.3.0 JDBC 4.0

DB:Oracle数据库11g

休眠4.3.8

代码:

Session session = sessionFactory.openSession();
Criteria fetchCriteria = session.createCriteria("Student");

Disjunction disjunction = Restrictions.disjunction();
for (int i = 1; i <= 10000; i++) {
Conjunction conjunction = Restrictions.conjunction();
conjunction.add(Restrictions.eq("RollNumber", i+""));
disjunction.add(conjunction);
}

fetchCriteria.add(disjunction);
long start1 = System.currentTimeMillis();
List  resultList = fetchCriteria.setFirstResult(0).setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP).list();
long end1 = System.currentTimeMillis();
System.out.println("Time took :"+(end1-start1) +"ms");

问题

  1. 如果我使用Hibernate 4.3.8+Oracle 8运行上述代码,所需时间不到5000毫秒
  2. 如果我用Hibernate 4.3.8+mariadb-java-client-2.70运行上面的代码,它需要超过40000毫秒

额外配置:我已在hibernate.cfg.xml中将hibernate.jdbc.fetch_size设置为100以及jdbc URL、用户名和密码。

调查结果:

  1. 在这两种情况下生成的查询是相同的,如果我执行使用SQL客户端查询时,ORACLE需要10-11秒,MariaDB需要41-42秒
  2. 如果我使用JDBC调用,则由两个数据库生成的查询程序(对于ORACLE和MariaDB)大约需要600毫秒

注意:两个表(Oracle和MariaDB)都有15000条记录。

有人能帮我为什么MariaDB需要时间吗?或者需要一些额外的设置来提高MariaDB的性能。我已经尝试了defaultFetchSize,它在https://mariadb.com/kb/en/about-mariadb-connector-j/但没有运气。

数据库生成的SQL查询:

select  this_.rollNo as RollNo1_0_0_, this_.VersionID as Version2_0_0_,
this_.Name as Name3_0_0_, this_.dept as dept4_0_0_,
this_.favSubj as favSubj5_0_0_,
this_.ID as ID33_0_0_
from  Student this_
where  ((this_.ID='1')
or  (this_.ID='2')
or  (this_.ID='3')
or  ....
or  (this_.ID='10000') 

MariaDB DDL

CREATE TABLE `student` (
`RollNo` bigint(20) NOT NULL ,
`VersionID` bigint(20) NOT NULL,
`Name` varchar(100) COLLATE ucs2_bin DEFAULT NULL,
`dept` varchar(100) COLLATE ucs2_bin DEFAULT NULL,
`favSubj` varchar(100) COLLATE ucs2_bin DEFAULT NULL,
`ID` varchar(100) COLLATE ucs2_bin DEFAULT NULL,
PRIMARY KEY (`RollNo`),
UNIQUE KEY `UK_student` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=20258138 DEFAULT CHARSET=ucs2 COLLATE=ucs2_bin

Oracle DDL

CREATE TABLE student (
RollNo NUMBER(19,0), 
VersionID NUMBER(19,0) NOT NULL ENABLE,
Name VARCHAR2(100),
dept  VARCHAR2(100),
favSubj VARCHAR2(100),
ID VARCHAR2(100), 
PRIMARY KEY ("RollNo"),
CONSTRAINT "UK_student" UNIQUE ("ID")
)

MariaDB解释选择查询输出

类型<1th>可能的_keys<2th>ref><5th>额外this_><1000>>[/tr>
idselect_typekey_len>行
1SIMPLE范围UK_Student203NULL使用索引条件

具有10K项的OR需要很长时间才能解析。更快的是IN:

where  this_.ID IN ('1', '2', ..., '10000')

然而,即便如此,运行起来也可能需要很长时间。

在MariaDB的情况下,我认为优化器会说

  • 哦,太多了,我无法一一查找,所以
  • 相反,我将简单地扫描表格,检查该列表中每一行的ID(在10K长的列表中使用某种有效的查找)

但是,如果表中有20M行,则需要很长时间。

你能提供查询计划(EXPLAIN)吗?这样我们就可以确认我抵押的是什么?

这看起来合乎逻辑且更快,但将无法正确工作:

where  this_.ID BETWEEN '1' AND '10000'

因为这是一辆VARCHAR!!

性能--使id成为INT,而不是成为VARCHAR

最新更新