当前位置: 首页 > article >正文

node mysql和mysql2有什么区别

上次写了一篇node使用mysql的入门:你学废了吗:node使用mysql_node.js mysql8-CSDN博客,结果写完才发现mysql模块有一个新的版本:mysql2。那就来看看mysql2模块对比mysql模块有什么区别。

mysql模块的问题

nodejs的mysql模块虽然功能强大,但是由于发布的时间比较久,后续的版本有些地方跟不上大前端技术的迭代脚步(个人觉得是项目过于庞大,支持新的语法需要做大量的重构),还是存在一些缺点:

  1. 回调问题,mysql的操作都是通过回调函数来执行,这就回到了我们熟悉的“回调地狱”,过多的回调函数嵌套,会大大的破坏代码的可读性和可维护性。
  2. Promise和async/await,跟早起的node其他模块一样,mysql模块并不支持Promise和async/await语法,要使用这些语法,需要自形封装mysql的操作。
  3. 缺少高级功能支持,例如:语句预处理、流式查询等,对新版本的mysql支持不足(mysql8的密码加密格式问题等)
  4. 性能问题,在大数据量或者高并发的情况下,mysql模块会出现性能受限的情况,主要原因是其无法发挥nodejs的异步特性和性能特性。

针对上面的问题,mysql2做了很多改进,mysql2基于mysql-native项目进行改进,同时兼容mysql的API。

mysql2的使用

安装

npm install mysql2

建立链接

const mysql2 = require('mysql2');
const connection = mysql2.createConnection({
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'demo'
});

执行sql

// 查询
connection.query(
  'select * from demo',
  function(err, results, fields) {
    console.log(results);
  }
);

// 插入
connection.execute(
  'insert into demo set name="sk"',
   function(err, results, fields) {
    console.log(results);
  }
)

写法看起来跟mysql也没什么不一样,这主要是为了向下兼容。但是sql的执行结果会自动转换格式,不需要再自行处理:

connection.query(
  'select * from demo',
  function(err, results, fields) {
    console.log(results); //  [ { id: 1, name: '0' }, { id: 2, name: '1' } ]
  }
);

如果需要使用mysql2的新特性,需要引入对应的模块。

使用Promise和async/await

要使用promise的特性,需要引入promise的模块

const mysql2 = require('mysql2/promise'); // 替换掉原来的require('mysql2')

引入promise模块后就可以使用promise的写法:

// promise
mysql2.createConnection({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'demo'
}).then(res => {
    connection = res;
});

// async/await
const connection = await mysql2.createConnection({
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'demo'
});

// 查询
connection.query('select * from demo2').then(([results, fields]) => {
    console.log(results);
});

let [results, fields] = await connection.query('select * from demo2 where id > 3');

注意:这里返回的结果是一个数组,包括results和fields,results为执行的结果,fields为与结果相关的字段的元数据。

使用TypeScript

mysql2内置TS的支持。

import mysql2, { RowDataPacket } from 'mysql2';

const connection = mysql2.createConnection({
  host: 'localhost',
  user: 'root',
  password: '123456',
  database: 'demo'
});

connection.query<RowDataPacket[]>('select * from demo2', (err, rows) => {
  console.log(rows);
});

具体内容可以参考官方文档:https://github.com/sidorares/node-mysql2/blob/HEAD/documentation/en/TypeScript-Examples.md

其他

其他新特性包括连接池、流式查询等,这些涉及到其他的mysql知识点,后面有机会再聊,使用的方法可以参考官方文档:node-mysql2/documentation/en at 489154f98224fad8036b87c63df8b736ede1c4aa · sidorares/node-mysql2 · GitHub

mysql2与mysql的性能对比

mysql2官方说明第一个点就是它比mysql模块具备更好的性能。那么mysql2是怎么做到的?

首先,最大的点应该是使用了libmysqlclient,libmysqlclient是使用C语言实现的库,mysql2是基于该库开发,使得其可以跟mysql数据库进行低级别的通讯,从而提高性能和效率。使用编译后的库启动速度也更高。与mysql模块对比,mysql模块使用的是JavaScript实现的,没有依赖其他库,只能使用node底层的异步I/O和事件循环,这对其性能影响比较大。

其次,在协议解析器上做了更多的改进:

  1. 更高效的数据解析方式:采用更高效的数据解析方式,能更快地解析MySQL协议中的数据,如使用Buffer对象来存储数据,使用ES6的解构赋值来解析数据等,使得数据解析更加快速和高效。
  2. 更高效的数据序列化方式:采用了更高效的数据序列化方式,能更快地将数据序列化为MySQL协议中的格式。如使用ES6的模板字符串来生成SQL语句,使用Buffer对象来存储数据等。
  3. 增加流式解析的支持:数据可以在解析的同时被处理,不需要等待整个数据包解析完成。

其他的还有像连接池之类的,减少创建链接的额外开销等方式来减少性能消耗。

做个小实验

接下来我们来做个对比实验,我们在同一个数据库创建两个一样的表,分别用mysql和mysql2模块来进行插入和查询,对比下时间的消耗。

表结构如下,只有一个id和name,id自增。mysql使用demo1表,mysql2使用demo2表。

CREATE TABLE `demo1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(60) DEFAULT NULL COMMENT 'name',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='demo表1';

插入数据的代码:

function insertRow(i) {
    return new Promise((resolve, reject) => {
        connection.query(
            `insert into demo1 set name='${i}'`, 
            (error, results, fields) => {
                if (error) {
                    reject();
                    throw error;
                }
                resolve();
            }
        );
    });
}

async function run(times) {
    let i = 0;
  	console.time();
    for(i; i < times; i++) {
        await insertRow(i);
    }
    console.timeEnd();
}

为了尽量减少代码写法不一致带来的误差,mysql2使用向下兼容的代码,保证执行的代码一致。同时在相同配置的容器中执行代码,减少系统层面的误差。

我们执行代码,分别插入1000、4000、7000、10000条数据,每种次数执行5次,不会清表,看看两边的耗时对比:

次数

1000

4000

7000

10000

mysql

1

3.065s

13.784s

20.749s

27.704s

2

2.923s

11.573s

20.362s

27.652s

3

2.941s

11.941s

20.254s

31.822s

4

2.917s

11.767s

24.963s

31.362s

5

2.839s

11.457s

27.387s

31.450s

平均值

2.937s

12.104s

22.743s

29.997s

mysql2

1

3.085s

11.776s

19.406s

28.061s

2

2.830s

11.380s

19.229s

27.601s

3

2.850s

11.424s

19.157s

27.292s

4

2.874s

11.620s

19.070s

27.234s

5

2.790s

11.387s

23.615s

27.947s

平均值

2.885s

11.517s

20.095s

27.627s

可能在高频插入的情况下,mysql2的性能会更优一些:

接下来我们看看数据查询的情况:

查询的代码:

function select(rows) {
    console.time();
    connection.query(
        `select name from demo1 limit ${rows}`, 
        (error, results, fields) => {
            if (error) {
                throw error;
            }
            console.timeEnd();
        }
    );
}

我们分别查询:1000、5000、10000、20000、25000条数据,每次查询重复一次,看看性能的对比:

次数

1000

5000

10000

20000

25000

mysql

1

10.622ms

17.358ms

19.193ms

26.517ms

27.842ms

2

2.64ms

6.366ms

8.962ms

11.735ms

15.87ms

3

2.733ms

4.452ms

5.599ms

9.328ms

11.247ms

4

3.45ms

3.357ms

5.844ms

7.765ms

18.947ms

5

1.873ms

3.072ms

4.635ms

7.773ms

9.666ms

平均值

4.264ms

6.921ms

8.847ms

12.623ms

16.714ms

去除第一次平均值

2.674ms

4.312ms

6.260ms

9.1502ms

13.933ms

mysql2

1

35.555ms

40.431ms

43.244ms

48.772ms

48.815ms

2

1.636ms

4.386ms

6.949ms

12.606ms

13.701ms

3

1.736ms

3.822ms

6.46ms

7.888ms

15.633ms

4

1.556ms

3.351ms

3.906ms

12.852ms

10.309ms

5

1.577ms

2.727ms

3.317ms

5.998ms

12.669ms

平均值

8.412ms

10.943ms

12.775ms

17.623ms

20.225ms

去除第一次平均值

1.626ms

3.573ms

5.158ms

9.836ms

13.078ms

可以看到,mysql2在第一次查询的时候明显慢一些,应该是与底层建立链接的时间消耗比较大,之后的消耗的时间明显小于mysql。

但是这个性能还是不够强,使用mysql2的连接池和流式查询,再看看整体的性能:

const mysql = require('mysql2');

// 创建链接池
const pool =  mysql.createPool({
    host: 'local-mysql',
    port: 3306,
    user: 'root',
    password: '123456',
    database: 'demo',
    connectionLimit: 20 // 最多20个链接
});

// 执行查询
pool.getConnection(
    (err, connection) => { 
        if (err) {
          throw err;
        }
        const query = connection.query('select name from demo1 limit 10000');
        console.time();
        query
        .stream()
        .on('data', (row) => { })
        .on('error', (err) => {})
        .on('end', () => { 
            console.timeEnd(); 
          }); 
	}
);

执行结果如下:

次数

1000

5000

10000

20000

25000

1

4.855ms

11.471ms

15.148ms

18.993ms

20.689ms

2

2.421ms

7.133ms

8.781ms

13.117ms

14.738ms

3

2.64ms

3.72ms

4.863ms

7.158ms

7.498ms

4

1.522ms

3.18ms

5.483ms

6.909ms

7.451ms

5

1.241ms

2.417ms

4.493ms

5.801ms

8.017ms

性能明显提升了很多。

总结

本文对node的mysql和mysql2模块做了简单的对比,我们做了个小实验对比了两者在插入和查询的性能对比,当然这只是一个小实验,场景简单,样本也比较少,但是还是能看出mysql2的性能更优。从整个对比来看,mysql2在新技术特性适配和性能上明显优于mysql模块。如果是新项目或者项目比较好更新,建议使用mysql2,如果使用第三方封装的mysql库,可以看下是基于哪个mysq模块,如果没有依赖亦可以对比下其与mysql2的性能。


http://www.kler.cn/a/505875.html

相关文章:

  • 告别 Excel,拥抱 R 语言:开启数据分析新时代
  • 学成在线_内容管理模块_创建模块工程
  • FPGA 串口与HC05蓝牙模块通信
  • 使用PWM生成模式驱动BLDC三相无刷直流电机
  • 【ArcGIS微课1000例】0138:ArcGIS栅格数据每个像元值转为Excel文本进行统计分析、做图表
  • DolphinScheduler自身容错导致的服务器持续崩溃重大问题的排查与解决
  • 潜力巨大但道路曲折的量子计算:探索未来科技的无限可能
  • 系统学习算法:专题四 前缀和
  • Vue.js组件开发-如何自定义Element UI组件
  • 人民邮电出版社书籍信息爬虫
  • C/C++中,const、static关键字有什么作用,如何定义、初始化,什么情形下需要用到这两关键字?
  • util层注入service
  • RabbitMQ-交换机
  • Flink CDC 在阿里云实时计算Flink版的云上实践
  • [Qt]常用控件介绍-多元素控件-QListWidget、QTableWidget、QQTreeWidget
  • 再见IT!
  • [每周一更]-(第131期):Go并发协程总结篇
  • 如何在JS里进行深拷贝
  • K8S 节点选择器
  • Luggage Lock( The 2021 ICPC Asia Shenyang Regional Contest )
  • 《鸿蒙Next微内核:解锁人工智能决策树并行计算的加速密码》
  • (蓝桥杯)使用差分数组和前缀和解决区间更新问题——倒水
  • 9.7 visual studio 搭建yolov10的onnx的预测(c++)
  • 解锁企业数字化转型新力量:OpenCoze(开源扣子)
  • 备战蓝桥杯 队列和queue详解
  • git操作(bitbucket仓库)