再送一波干货,测试2000线程并发下同时查询1000万条数据库表及索引优化

方大帝的博客 方大帝的博客     2022-08-30     681

关键词:

这篇文章的知识点如下:

1.如何自写几十行代码就能模拟测试高并发下访问千万级数据库表

2.比较高并发下(200次/秒,2000次/秒,10000次/秒)数据库的性能

3.比较千万级数据库在查询时加索引与不加索引的巨大差异(说实话,这个测试结果让我自己本人也很惊讶)

针对上篇文章插入的1000万条数据到数据库后,我们进行了高并发下测试(模拟教师输入姓名和密码在1秒内登录数据库),线程类代码如下

package insert;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
public class ThreadToMysql extends Thread {
    public String teacherName;
    public String password;
    public ThreadToMysql(String teacherName, String password) {//构造函数传入要查询登录的老师姓名和密码
         
        this.teacherName=teacherName;
        this.password=password;
    }
     
    public void run() {
         String url = "jdbc:mysql://127.0.0.1/teacher"; 
         String name = "com.mysql.jdbc.Driver"; 
         String user = "root"; 
         String password = "123456"; 
        Connection conn = null; 
        try {
            Class.forName(name);
            conn = DriverManager.getConnection(url, user, password);//获取连接 
            conn.setAutoCommit(false);//关闭自动提交,不然conn.commit()运行到这句会报错
        } catch (ClassNotFoundException e1) {
            e1.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        if (conn!=null) {
            Long startTime=System.currentTimeMillis();//开始时间
            String sql="select id from t_teacher where t_name='"+teacherName+"' and t_password='"+password+"'";//SQL语句
            String id=null;
            try {
                Statement stmt=conn.createStatement();
                ResultSet rs=stmt.executeQuery(sql);//获取结果集
                if (rs.next()) {
                    id=rs.getString("id");
                }
                conn.commit();
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
                Long end=System.currentTimeMillis();
                System.out.println(currentThread().getName()+"  查询结果:"+id+"   开始时间:"+startTime+"  结束时间:"+end+"  用时:"+(end-startTime)+"ms");
             
             
        } else {
            System.out.println(currentThread().getName()+"数据库连接失败:");
        }
    }
     
}

   测试类代码如下:

package insert;
 
public class TestThreadToMysql {
 
    public static void main(String[] args) {
        for (int i = 1; i <=2000; i++) {
            String teacherName=String.valueOf(i);
            new ThreadToMysql(teacherName, "123456").start();
     
 
}

  

 一.在没有加索引的情况下测试:

把数据库的最大连接数设置为250:

测试代码:

package insert;
 
public class TestThreadToMysql {
 
    public static void main(String[] args) {
        for (int i = 1; i <=200; i++) {
            String teacherName=String.valueOf(i);
            new ThreadToMysql(teacherName, "123456").start();
        }
    }
 
}

  测试结果:

100多秒啊。。。我的天,这用户体验也没准了O(∩_∩)O哈哈~

二.加索引后再次进行高并发下测试:

数据库加索引SQL语句如下:这里我有一个疑问,上个星期我加索引等了半个小时我都没加完索引我就停止了,今天下午居然只用了551秒就加完了索引。。。搞不懂

clean下项目代码后再次运行(尽量经常clean下项目去掉缓存,不然结果会有出入):

看到这个结果有没有被惊呆啊?哈哈加了索引由100多秒提升到1~2毫秒,查询速度提示1万多倍,查询性能得到大幅度变态级提升~~~

没加索引之前我查询单个记录都要2秒多

用explain查看语句可以知道要扫描全表,性能当然大幅度下降

 

 

 

 

 

下面我们来挑战2000线程同时并发访问查询数据库。看看结果:

把数据库最大连接数设置为2500

测试代码改为2000

package insert;
 
public class TestThreadToMysql {
 
    public static void main(String[] args) {
        for (int i = 1; i <=2000; i++) {
            String teacherName=String.valueOf(i);
            new ThreadToMysql(teacherName, "123456").start();
        }
    }
 
}

  结果截图:

性能没问题,平均几十毫秒,很满意

下面我们来挑战一下1万个线程同时高并发访问,大家可以先想想结果会怎么样,哈哈

设置数据库最大连接数12000

测试代码改为10000(再次提示。clean一下项目去掉缓存,这样结果更准确)

package insert;
 
public class TestThreadToMysql {
 
    public static void main(String[] args) {
        for (int i = 1; i <=10000; i++) {
            String teacherName=String.valueOf(i);
            new ThreadToMysql(teacherName, "123456").start();
        }
    }
 
}

  结果如下(运行后发现电脑有点卡):

结果出现两种报错,1.连接请求被拒绝 2.连接失效 3.不过也有一部分成功连接上并且正确运行

然后我在数据库查看最大连接响应数:

可以看出来就算你的数据库设置为再高你的数据库服务器也响应不过来。。。。顶多响应5758个

100多秒啊。。。我的天,这用户体验也没准了O(∩_∩)O哈哈~

二.加索引后再次进行高并发下测试:

数据库加索引SQL语句如下:这里我有一个疑问,上个星期我加索引等了半个小时我都没加完索引我就停止了,今天下午居然只用了551秒就加完了索引。。。搞不懂

clean下项目代码后再次运行(尽量经常clean下项目去掉缓存,不然结果会有出入):

看到这个结果有没有被惊呆啊?哈哈加了索引由100多秒提升到1~2毫秒,查询速度提示1万多倍,查询性能得到大幅度变态级提升~~~

没加索引之前我查询单个记录都要2秒多

用explain查看语句可以知道要扫描全表,性能当然大幅度下降

 

 

 

 

 

下面我们来挑战2000线程同时并发访问查询数据库。看看结果:

把数据库最大连接数设置为2500

测试代码改为2000

 

关于并发下内存及cpu使用情况的思考

鉴于昨天的文章<<使用Interlocked在多线程下进行原子操作,无锁无阻塞的实现线程运行状态判断>>里面有一个封装好的无锁的类库可以判断并发下的结束状况,我们可以完成并发时,以及并发的同时做一些事,因此,今天... 查看详情

性能测试的过程(jmeter)

 一.web性能测试的准备工作1.项目背景访问地址访问环境:windows2.需求并发登陆的性能(要求多少个用户登录)3.场景60秒内运行100个线程线程在20、50、100并发下的表现4.监控成功率、响应时间、标准差、cpu、IO资源监控需在lin... 查看详情

高并发下如何避免产生重复数据?(代码片段)

...原因之后发现,这个事情没想象中简单,可以说一波多折。1.需求产品有个需求:用户选择一些品牌,点击确定按钮之后,系统需要基于一份默认品牌的商品数据,复制出一批新的商品。拿到这个需求时觉... 查看详情

高并发下如何避免产生重复数据?(代码片段)

...原因之后发现,这个事情没想象中简单,可以说一波多折。1.需求产品有个需求:用户选择一些品牌,点击确定按钮之后,系统需要基于一份默认品牌的商品数据,复制出一批新的商品。拿到这个需求时觉... 查看详情

性能测试之场景设计

负载测试需求举例:系统支持200个并发,用户信息查询的响应时间小于5秒场景设计:200个并发持续运行20分钟,通过测试结果验证用户信息查询的响应时间是否小于5秒。 压力测试需求举例:系统在50,100,150,200并发下的运... 查看详情

hashmap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么

Hashmap在并发环境下,可能出现的问题:1、多线程put时可能会导致get无限循环,具体表现为CPU使用率100%;原因:在向HashMapput元素时,会检查HashMap的容量是否足够,如果不足,则会新建一个比原来容量大两倍的Hash表,然后把数组... 查看详情

深入解析tiflash丨多并发下线程创建释放的阻塞问题(代码片段)

TiFlash初期存在一个棘手的问题:对于复杂的小查询,无论增加多少并发,TiFlash的整机CPU使用率都远远不能打满。如下图:对TiFlash和问题本身经过一段时间的了解后,认为方向应该在“公共组件”(全局锁... 查看详情

高并发下线程安全的单例模式

...现方式,你是否都了解呢?高并发下如何保证单例模式的线程安全性呢?如何保证序列化后的单例对象在反序列化后任然是单例的呢?这些问题在看了本文之后都会一一的告诉你答案,赶快来阅读吧!什么是单例模式?在文 查看详情

高并发下springcloud hystrix的严重问题?

...1部分我使用HystrixCommand进行服务,并使用jmeter进行高并发测试。测试结果太差了,看流。代码->@HystrixCommand(fallbackMethod="helloF 查看详情

[java]_[初级]_[并发下使用atomicreference来保证原子读写对象](代码片段)

场景在开发Java多线程程序时,和C/C++一样会遇到多线程同时修改共享对象的问题。比如一个缓存HashMap需要更新,那么可以使用标准库的ConcurrentHashMap来替换HashMap作为共享对象。如果是自定义的对象呢,并发访问... 查看详情

缓存击穿

...3.数据一致性 ↑↓二。什么是缓存击穿在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,缓存失去存在的意义.打个比方,数据库是人,缓存是防弹衣,子弹... 查看详情

高并发下的web异步处理方案(代码片段)

...务处理基本都是同步处理,即业务处理与web容器接收线程为同一线程,每一次Http请求都由一个线程从头到尾负责处理。​如果一个请求业务处理涉及IO操作,比如访问数据库、调用第三方服务 查看详情

并发下的集合(代码片段)

ArrayList是一个线程不安全的容器如下列程序packagecom.longfor.dragonshard.service.cost.standard.impl;importjava.util.ArrayList;publicclassArrayListMultiThreadprivatestaticArrayListarrayList=newArrayList();publicstatic 查看详情

高并发下service层的写法(代码片段)

...段代码里,因为加了synchronized进行修饰,所以无论多少个线程过来,只会有一个线程对锁住的代码块进行操作 查看详情

高并发下缓存失效问题及解决方案

缓存穿透介绍:当查询一个不存在的数据,此时缓存是不命中的,就会去查询db,这将导致每次查询这个不存在的数据都要去访问db,缓存就没有意义了。如果不怀好意的人利用不存在的数据进行攻击,可能导致数据库崩溃解决... 查看详情

强制同时修改变量 (C++)

...8-11-2114:15:45【问题描述】:我正在尝试对原子库进行单元测试(我知道原子库不适合进行单元测试,但我仍然想尝试一下)为此,我想让X个并行线程增加一个计数器并计算结果值(应该是X)。代码如下。问题是它永远不会中断... 查看详情

高并发下缓存失效问题及解决方案

缓存穿透介绍:当查询一个不存在的数据,此时缓存是不命中的,就会去查询db,这将导致每次查询这个不存在的数据都要去访问db,缓存就没有意义了。如果不怀好意的人利用不存在的数据进行攻击,可能导致数据库崩溃解决... 查看详情

高并发下的java数据结构(list,set,map,queue)

...直接在并发环境下正常工作,这是因为这些数据结构不是线程安全的。本节将着重介绍一些可以用于多线程环境的数据结构,如并发List、并发Set、并发Map等。1.并发ListVector或者CopyOnWriteArrayList是两个线程安全的List实现,ArrayList... 查看详情