【问题标题】:Java - MariaDB Perfoming slow with Hibernate criteriaJava - MariaDB 使用 Hibernate 标准执行缓慢
【发布时间】:2021-05-04 05:21:31
【问题描述】:

环境:

mariadb-java-client-2.7.0

数据库:MariaDB 10.5.7

ojdbc8 - Oracle 11.2.0.3.0 JDBC 4.0

数据库: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.7.0 运行上述代码,则需要超过 40,000 毫秒。

额外配置: 我在 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)都有 15,000 条记录。

谁能帮助我为什么 MariaDB 需要时间? 或者需要一些额外的设置来提高 MariaDB 的性能。 我试过https://mariadb.com/kb/en/about-mariadb-connector-j/中提到的defaultFetchSize,但没有运气。

数据库生成的 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 table type possible_keys key key_len ref rows Extra
1 SIMPLE this_ range UK_Student UK_Student 203 NULL 10000 Using index condition

【问题讨论】:

  • 请提供生成的SQL和表定义。
  • 请咨询您的 DBA。您可能缺少 Oracle 中的 MariaDB 索引。
  • @RickJames 添加表定义并生成 SQL。
  • @ChristianBeikov 索引正确。
  • 我猜 Oracle 在优化/执行这个查询方面比 MariaDB 更好。使用EXPLAIN 查看 MariaDB 生成的查询计划并将其与 Oracle 的查询计划进行比较。它还取决于运行数据库的机器。

标签: java oracle hibernate mariadb mariadb-connect-engine


【解决方案1】:

具有 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

【讨论】:

    猜你喜欢
    • 2019-03-05
    • 2014-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    相关资源
    最近更新 更多