From cc407ad2b9af00348e88b335e59b8db1fe62193e Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 25 Jan 2019 23:00:19 +0800 Subject: [PATCH] update --- Home.md | 1 + _Sidebar.md | 1 + 分区分表.md | 40 ++++++++++++++++ 性能.md | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 分区分表.md create mode 100644 性能.md diff --git a/Home.md b/Home.md index d774fe9..0628d25 100644 --- a/Home.md +++ b/Home.md @@ -48,6 +48,7 @@ FreeSql是一个功能强大的NETStandard库,用于对象关系映射程序(O * [日期/时间](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0#%e6%97%a5%e6%9c%9f) * [其他](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0#%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0%e5%85%a8%e8%a7%88) * [读写分离](https://github.com/2881099/FreeSql/wiki/%e8%af%bb%e5%86%99%e5%88%86%e7%a6%bb) +* [性能](https://github.com/2881099/FreeSql/wiki/%e6%80%a7%e8%83%bd) * API参考 ## 使用指南 diff --git a/_Sidebar.md b/_Sidebar.md index b9f8e20..cc17db6 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -34,6 +34,7 @@ * [日期/时间](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0#%e6%97%a5%e6%9c%9f) * [其他](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0#%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0%e5%85%a8%e8%a7%88) * [读写分离](https://github.com/2881099/FreeSql/wiki/%e8%af%bb%e5%86%99%e5%88%86%e7%a6%bb) +* [性能](https://github.com/2881099/FreeSql/wiki/%e6%80%a7%e8%83%bd) * API参考 ## 使用指南 diff --git a/分区分表.md b/分区分表.md new file mode 100644 index 0000000..081090e --- /dev/null +++ b/分区分表.md @@ -0,0 +1,40 @@ +## 分区 + +分区就是把一个数据表的文件和索引分散存储在不同的物理文件中。把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上,数据库不同现实方式有所不同。 + +与分表不同,一张大表进行分区后,他还是一张表,不会变成二张表,但是他存放数据的区块变多了。分区的概念,我觉得就想突破磁盘I/O瓶颈,想提高磁盘的读写能力,来增加数据库的性能。 + +分区实现是比较简单的,建立分区表,根建平常的表没什么区别,并且对开发代码端来说是透明。 + +postgresql10以上的自动分区分表功能: + +1、首先创建主分区表: +```sql +create table fenbiao( +id int, +year varchar +) partition by list(year) +``` + +这里设置的是根据year列进行数据分表;创建后使用navicat是看不到的; + +2.创建分表: +```sql +create table fenbiao_2017 partition of fenbiao for values in ('2017'); +create table fenbiao_2018 partition of fenbiao for values in ('2018'); +``` + +这样这两天数据会依靠规则插入到不同分表中,如果插入一条不符合规则的数据,则会报错误:no partition of relation "fenbiao" found for row. + +## 分表 + +分表从表面意思上看呢,就是把一张表分成N多个小表,每一个小表都是完正的一张表。分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。 + +分表后单表的并发能力提高了,磁盘I/O性能也提高了。并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出现高并发的话,总表可以根据不同 的查询,将并发压力分到不同的小表里面。 + +## 分库分表 + +分库分表把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上。 + +数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,一台服务器的资源(CPU、磁盘、内存、IO等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。 + diff --git a/性能.md b/性能.md new file mode 100644 index 0000000..f32da50 --- /dev/null +++ b/性能.md @@ -0,0 +1,135 @@ +FreeSql现实了强大的功能的同时,性能并没有受影响,使用反射或耗时的操作都做了缓存处理。读取数据部分采用了ExpressionTree,使得FreeSql解析实体数据的速度与Dapper非常接近。 + +## 查询性能测试结果 + +```csharp +IFreeSql mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=100") + .UseLogger(new LoggerFactory().CreateLogger("FreeSql.MySql")) + //由于null会默认输出日志到控制台,影响测试结果。这里传入一个空的日志输出对象 + .UseAutoSyncStructure(false) + //关闭自动迁移功能 + .Build(); + +class Song { + public int Id { get; set; } + public string Title { get; set; } + public string Url { get; set; } + public DateTime Create_time { get; set; } + public bool Is_deleted { get; set; } +} +``` + +测试方法忽略第一次执行结果,以第二次执行结果为准。 + +| | 数量 | Dapper | FreeSql | | +| - | - | - | - | - | +| [执行SQL返回实体列表](#%e6%89%a7%e8%a1%8cSQL%e8%bf%94%e5%9b%9e%e5%ae%9e%e4%bd%93%e5%88%97%e8%a1%a8) | 131072 | 00:00:00.6234959 | 00:00:00.6470552 | | +| [执行SQL返回元组列表](#%e6%89%a7%e8%a1%8cSQL%e8%bf%94%e5%9b%9e%e5%85%83%e7%bb%84%e5%88%97%e8%a1%a8) | 131072 | 00:00:00.4242411 | 00:00:00.5773532 | | +| [执行SQL返回dynamic列表](#%e6%89%a7%e8%a1%8cSQL%e8%bf%94%e5%9b%9edynamic%e5%88%97%e8%a1%a8) | 131072 | 00:00:00.6448897 | 00:00:00.9447454 | (不推使用) | +| [Dapper.Query VS FreeSql.ToList](Dapper.Query+VS+FreeSql.ToList) | 131072 | 00:00:00.6001112 | 00:00:00.6228980 | (使用频率最高) + +好吧,FreeSql认输,你可能有疑问为什么比Dapper慢,总能看到某某orm宣称性能超过Dapper多少,都是Emit或ExpressionTree再比已经没有意义。 + +FreeSql支持更复杂的数据库类型解析,有一些类型需要递归或循环才能解析到正确的值,如果还说比Dapper快那是在欺骗自己和世界。 + +目前的性能可以说相差无及,并且真实项目的性能损耗更多不在这个环节,应该用更优的设计来提升性能。 + +> 由于Dapper没有批量插入/更新/删除的功能,并且都是执行一条SQL命令,测试结果没有意义。 + +> FreeSql批量插入使用的命令:INSERT INTO Song (...) VALUES(...),VALUES(...),VALUES(...)... + +### 执行SQL返回实体列表 + +```csharp +[Fact] +public void QueryEntity() { + var sb = new StringBuilder(); + var time = new Stopwatch(); + + time.Restart(); + List dplist1 = null; + using (var conn = g.mysql.Ado.MasterPool.Get()) { + dplist1 = Dapper.SqlMapper.Query(conn.Value, "select * from song").ToList(); + } + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper"); + + time.Restart(); + var t3 = g.mysql.Ado.Query("select * from song"); + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {t3.Count}; ORM: FreeSql*"); +} +``` + +### 执行SQL返回元组列表 + +```csharp +[Fact] +public void QueryTuple() { + var sb = new StringBuilder(); + var time = new Stopwatch(); + + time.Restart(); + List<(int, string, string)> dplist2 = null; + using (var conn = g.mysql.Ado.MasterPool.Get()) { + dplist2 = Dapper.SqlMapper.Query<(int, string, string)>(conn.Value, "select * from song").ToList(); + } + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {dplist2.Count}; ORM: Dapper"); + + time.Restart(); + var t4 = g.mysql.Ado.Query<(int, string, string)>("select * from song"); + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {t4.Count}; ORM: FreeSql*"); +} +``` + +### 执行SQL返回dynamic列表 + +```csharp +[Fact] +public void Query() { + var sb = new StringBuilder(); + var time = new Stopwatch(); + + time.Restart(); + List dplist3 = null; + using (var conn = g.mysql.Ado.MasterPool.Get()) { + dplist3 = Dapper.SqlMapper.Query(conn.Value, "select * from song").ToList(); + } + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {dplist3.Count}; ORM: Dapper"); + + time.Restart(); + var t5 = g.mysql.Ado.Query("select * from song"); + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {t3.Count}; ORM: FreeSql*"); +} +``` + +### Dapper.Query VS FreeSql.ToList + +```csharp +[Fact] +public void Query() { + var sb = new StringBuilder(); + var time = new Stopwatch(); + + time.Restart(); + var t3 = g.mysql.Select().ToList(); + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*"); + + time.Restart(); + List dplist1 = null; + using (var conn = g.mysql.Ado.MasterPool.Get()) { + dplist1 = Dapper.SqlMapper.Query(conn.Value, "select * from song").ToList(); + } + time.Stop(); + sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper"); +} +``` + +> 更多测试源码:FreeSql/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs +