0

环境:

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 以及 jdbc URL、用户名和密码设置为 100。

发现:

  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

甲骨文 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 选择类型 桌子 类型 可能的键 钥匙 key_len 参考 额外的
1 简单的 这个_ 范围 UK_学生 UK_学生 203 无效的 10000 使用索引条件
4

1 回答 1

0

具有OR10K 项的解析需要很长时间。更快的是IN

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

但是,即使这样也可能需要很长时间才能运行。

对于 MariaDB,我认为优化器会说

  • 哦,那东西太多了,我一个一个都查不出来,所以
  • 相反,我将简单地扫描表,检查ID该列表中的每一行(使用 10K 长列表中的某种有效查找)。

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

您能否提供查询计划 (EXPLAIN),以便我们确认我的假设?

这似乎合乎逻辑且更快,但无法正常工作:

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

因为它是一个VARCHAR!

性能——做id一个INT而不是一个VARCHAR

于 2021-02-01T18:35:16.373 回答