我等农民阶级实现数据库压力测试与索引实验的一个方法

八仙过海,各显神通。
但我等农民阶级还是有不会写数据库作业的人在。

这里提供一种实现数据库压力测试与索引实验的方法,简单为主,仅供参考。
本文PHP代码只能在linux环境下编译运行。
方法跨平台。

2019-12-10更新
(Python玩家可以了解一下multiprocessing模块下的process类)

首先理解并发与并行:
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。

并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

更简单的解释:
并行指的是多件事同时存在,同时执行
并发指的是多件事同时存在,交替执行

本文的实现环境

Quantity
1
Device
1 Cores / 1 GB / 30 GB SSD / Seattle
Operating System
Centos 7

 

概要:
每次插入8000条数据,开启126个进程。每秒查询一次,执行600次。

前提:
一个可以插入n条数据的存储过程,假设它叫做insert_form。本文的n为8000。
去了解使用pctnl_fork或者其他方式复刻进程的方法。
本文方法原理详见https://www.dostarve.xyz/index.php/2019/11/27/pcntl_fork/

插入数据的代码如下:

    $myfile = fopen("recordinsert.txt", "w") or die("Unable to open file!");
    $t3 = microtime(true);
    for( $i = 1; $i <= 6 ; $i++ ){
        $pid = pcntl_fork();
        if($pid == -1){
            die('could not fork');
        }
        else if( $pid ){
            $conn=new mysqli("localhost","root","password");
            if(! $conn ){
                die('连接失败: ' . mysqli_error($conn));
            }
            mysqli_query($conn , "set names utf8");    // 设置编码,防止中文乱码
            mysqli_select_db($conn, 'database' );
            $sql = 'call insert_form';  //调用插入数据的存储过程
            $t1 = microtime(true);
            $retval = mysqli_query( $conn, $sql);        
            $t2 = microtime(true);
            $time = round($t2-$t1,3)."\n";
            echo '耗时'.round($t2-$t1,3).'秒';
            fwrite($myfile, $time);
            if(! $retval ){
                die('无法读取数据: ' . mysqli_error($conn));
            }
            else {
                echo ("插入成功\n");
            }
            mysql_close($conn);
        }
        else{
            $conn=new mysqli("localhost","root","password");
            if(! $conn ){
                die('连接失败: ' . mysqli_error($conn));
            }
            mysqli_query($conn , "set names utf8");    // 设置编码,防止中文乱码
            mysqli_select_db($conn, 'database' );
            $sql = 'call insert_form';
            $t1 = microtime(true);
            $retval = mysqli_query( $conn, $sql);        
            $t2 = microtime(true);
            $time = round($t2-$t1,3)."\n";
            echo '耗时'.round($t2-$t1,3).'秒';
            fwrite($myfile, $time);
            if(! $retval ){
                die('无法读取数据: ' . mysqli_error($conn));
            }
            else {
                echo ("插入成功\n");
            }
            mysql_close($conn);
        }
    }
    $t4 = microtime(true);
    echo '总耗时'.round($t4-$t3,3).'秒';
?>

查询数据的代码如下:

<?php
    $myfile = fopen("recordselect.txt", "w") or die("Unable to open file!");
    for ($i = 0; $i < 600; $i++) {
        $conn=new mysqli("localhost","root","password");
        if(! $conn ){
            die('连接失败: ' . mysqli_error($conn));
        }
        mysqli_query($conn , "set names utf8");    // 设置编码,防止中文乱码
        mysqli_select_db($conn, 'database' );
        $sql = 'select xxx from table where xxx'; //自己编写查询的sql语句
        $t1 = microtime(true);
        $retval = mysqli_query( $conn, $sql);        
        $t2 = microtime(true);
        echo '耗时'.round($t2-$t1,3).'秒';
        $time = round($t2-$t1,3)."\n";
        fwrite($myfile, $time);
        if(! $retval ){
            die('无法读取数据: ' . mysqli_error($conn));
        }
        else {
            echo ("查询成功\n");
        }
        mysql_close($conn);
        sleep(1);
    }
    fclose($myfile);
?>

先运行查询数据的php文件,再运行插入数据的php文件。
然后等它运行完毕就能在txt文件中看到每次插入/查询的时间。
无索引有索引各跑一遍。
一个小问题:考虑到查询时间,其实我并没有实现每秒查一次的效果。

有了数据之后使用python开始绘图。

import matplotlib
import matplotlib.pyplot as plt

input_txt = 'recordinsert.txt'
input_txt1 = 'recordselect.txt'
input_txt2 = 'recordinsert1.txt'
input_txt3 = 'recordselect1.txt'
x = []
y = []
x1 = []
y1 = []
x2 = []
y2 = []
x3 = []
y3 = []
f = open(input_txt)
f1 = open(input_txt1)
f2 = open(input_txt2)
f3 = open(input_txt3)
i = 1
for line in f:
    line = line.split('\n')

    x.append(i)
    i = i+1
    y.append(float(line[0]))

f.close

i = 1
for line in f1:
    line = line.split('\n')

    x1.append(i)
    i = i+1
    y1.append(float(line[0]))

f1.close


i = 1
for line in f2:
    line = line.split('\n')

    x2.append(i)
    i = i+1
    y2.append(float(line[0]))

f2.close

i = 1
for line in f3:
    line = line.split('\n')

    x3.append(i)
    i = i+1
    y3.append(float(line[0]))

f3.close

fig = plt.figure()
plt.plot(x, y, label='insert without index')
#plt.plot(x1, y1, label='select without index')
plt.plot(x2, y2, label='insert with index')
#plt.plot(x3, y3, label='select with index')
plt.margins(0)
plt.xlabel("time")
plt.ylabel("consuming")
plt.title("record")
plt.tick_params(axis="both")
plt.legend()

fig.savefig("f4.png")

我的图是这样的

2019/12/1 修正:下图图例反了

本文作者水平有限,如有问题欢迎在评论区交流。

 

发表评论