环境:
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");
问题
- 如果我使用Hibernate 4.3.8+Oracle 8运行上述代码,所需时间不到5000毫秒
- 如果我用Hibernate 4.3.8+mariadb-java-client-2.70运行上面的代码,它需要超过40000毫秒
额外配置:我已在hibernate.cfg.xml中将hibernate.jdbc.fetch_size设置为100以及jdbc URL、用户名和密码。
调查结果:
- 在这两种情况下生成的查询是相同的,如果我执行使用SQL客户端查询时,ORACLE需要10-11秒,MariaDB需要41-42秒
- 如果我使用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解释选择查询输出
id | select_type | 表 | 类型<1th>可能的_keyskey_len | <2th>ref>>行 | <5th>额外||||
---|---|---|---|---|---|---|---|---|
1 | SIMPLE | this_范围 | >UK_Student | 203 | NULL | <1000>>使用索引条件 | [/tr>
具有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
!