写在前面的话

公司一直在用MySql,最近由于业务量增大,数据压力也越来越大,MySQL的问题也逐渐暴露出来,之前只听说mysql性能不行,没想到几千条数据之间的关联查询也卡到需要优化的地步。

我之前用过很长一段时间的SqlServer,一般是数据量达到十万级以上才开始进行优化,几千条数据的表都是随便写逻辑的,从来不考虑性能问题,这让我产生了兴趣,想看看MySQL性能到底有多差。

既然要测评,所幸把最近非常火的PostgreSql和DB界老大Oracle也拉出来一起玩玩。

由于第一次接触PostgreSql和Oracle,配置方面不太了解,以下对这两种数据库的测试结果可能不是最优情况。Oracle大神勿喷。

测试环境

阿里云服务器 4核16G内存

Windows Server2012R2 x64

5Mbps带宽

高效云盘(2120IOPS)

数据库版本

MySql 8.0.19

Oracle 11G 企业版

MSSqlServer 2012 企业版

PostgreSql 13.3-2

数据库脚本(仅mysql)

数据库脚本只粘mysql的了,其他几种数据库大同小异

CREATE TABLE `itest_table`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `str` varchar(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL,
  `iname` varchar(50) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `inameindex`(`iname`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = gbk COLLATE = gbk_chinese_ci ROW_FORMAT = Dynamic;

测试程序

测试程序 java + springboot + mybatis

为了贴近实际的生产环境,是用java程序在本地进行的测试,而数据库是在服务器上,所以测试结果可能受网络影响。

但考虑到生产环境下的执行效率也会受到网络和代码逻辑的影响,所以感觉本测试虽然不如专业的数据库测评结果准确,但是却更实用。

四种数据库是一套程序,仅数据源不同

//实体
import lombok.Data;

@Data
public class ItestTable {
    int id;
    String str;
    String iname;
}
//mapper
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface ItestTableMapper {

    @Select("select * from itest_table")
    public List<ItestTable> selectAll();

    @Select("select * from itest_table where str like '%${str}%'")
    public List<ItestTable> selectByStr(@Param("str")String str);

    @Select("select * from itest_table where iname = #{iname}")
    public List<ItestTable> selectByIname(@Param("iname")String iname);

    @Insert("insert into itest_table(str,iname) values(#{str},#{iname})")
    public void insert(@Param("str") String str, @Param("iname") String iname);

    @Update("update itest_table set str = '修改后' where iname = '乙'")
    public void update();
}
//测试用例
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
@Slf4j
class SpringbootDemoApplicationTests {
    @Autowired
    ItestTableMapper itestTableMapper;

    //首先清空全部数据

    @Test
    void insert1000()
    {
        String str = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨";
        String[] nameAyy = new String[]{"甲","乙","丙","丁","戊","己","庚","辛"};
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            itestTableMapper.insert(str+i,nameAyy[i%4]);
        }
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

    @Test
    void select1000(){
        long stime = System.currentTimeMillis();
        List<ItestTable> list = itestTableMapper.selectAll();
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

    @Test
    void insert10000()
    {
        String str = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨";
        String[] nameAyy = new String[]{"甲","乙","丙","丁","戊","己","庚","辛"};
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            itestTableMapper.insert(str+i,nameAyy[i%4]);
        }
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

    @Test
    void select11000(){
        long stime = System.currentTimeMillis();
        List<ItestTable> list = itestTableMapper.selectAll();
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

    //此时创建索引
    @Test
    void insert10000WithIndex()
    {
        String str = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨";
        String[] nameAyy = new String[]{"甲","乙","丙","丁","戊","己","庚","辛"};
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            itestTableMapper.insert(str+i,nameAyy[i%4]);
        }
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }
    @Test
    void selectNoIndex(){
        long stime = System.currentTimeMillis();
        List<ItestTable> list = itestTableMapper.selectByStr("1");
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }
    @Test
    void selectWithIndex(){
        long stime = System.currentTimeMillis();
        List<ItestTable> list = itestTableMapper.selectByIname("甲");
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

    @Test
    void update()
    {
        long stime = System.currentTimeMillis();
        itestTableMapper.update();
        long etime = System.currentTimeMillis();
        System.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }

}

测试结果

单位:毫秒

测试结论

1.Oracle作为DB界扛把子,测评结果却不尽如人意,与网上的评价不符,怀疑是我配置的有问题,毕竟今天是我第一次安装使用Oracle,感觉安装麻烦、配置复杂,不会配置效率还超低,而且还收费!直接弃用。

2.MySql读写性能全面败北,优点是配置简单,且生态系统完善,有很多基于MySql开发的组件、工具,作为java程序员,想要完全放弃MySql几乎不可能;但MySql确实也不适合作为复杂业务的主力数据库,由于其轻量级的特点,可以作为辅助库参与系统。

3.PostgreSql最近的火爆也不是没有理由,作为完全开放源代码的数据库,插入性能方面完全碾压MySql,查询性能也毫不逊色。重点是安装配置极为简单,Oracle和PostgreSql同样为第一天接触,PostgreSql的上手难度比Oracle低很多。在不考虑生态的情况下,PostgreSql可以完全替代MySQL。若作为主力数据库,查询效率还是略显不足。

4.MSSqlServer的插入速度比Oracle稍有逊色,但是查询效率完全碾压其他三种数据库。有着令人意想不到的10倍的差距。而且文件体积也比较小。

我相信在Oracle大神的手中,Oracle性能可以碾压SqlServer,但是SqlServer却可以实现开箱即用,非常适合中小型公司的项目,且正版价格比Oracle低不少。