要用魔法打败魔法。巴啦啦能量~小魔仙全身变!
SqlServer优化
sqlserver Not in 优化
not in 优化
当需要过滤的数据比较少时用not in
当需要过滤的数据比较多时用not exists
比如你查询一张表,表里的数据只有几百条或者几千条就可以选择用not in
如果表里的数据量上万了那就选择用 not exists
not in 用法
select * from tablename where id not in (''''')
not exists 用法
select * from tablename where id not exists (.....)
sqlserver格式化表
TRUNCATE TABLE TbName --TbName是表名
ORM框架的选择
SqlSugar
SqlSugar是国人开发者开发的一款基于.NET的ORM框架,是可以运行在.NET 4.+ & .NET CORE的高性能、轻量级 ORM框架,众多.NET框架中最容易使用的数据库访问技术。
具有超越Dapper的性能 ,走的是EMIT结构中间语言动态编译到程序集,完成高性能的实体绑定,达到原生水平
特点:
- 开源、免费
- 国内开发者开发、维护;
- 支持.NET Core;
- 支持主流数据库,如:SQL Server,MySql,Oracle,Sqlite等;
- 维护更新及时
这里有它的详细介绍:传送门
PetaPoco
PetaPoco是一款适用于.NET应用程序的轻型对象关系映射器(ORM, Object Relational Mapper)。与那些功能完备的ORM(如NHibernate或Entity Framework)不同的是,PetaPoco更注重易用性和性能,而非丰富的功能。使用PetaPoco只需要引入一个C#文件,可以使用强类型的 POCO(Plain Old CLR Object),并支持使用T4模板生成的类等等 性能不如dapper,但仅次于他
特点:
- 开源、免费
- 可与SQL Server、SQL Server CE、MySQL、PostgreSQL以及Oracle数据库协同工作。
- 包含针对Insert/Delete/Update/Save以及IsNew的多个辅助方法。
- 支持简单事务
- 对于翻页请求会自动计算总记录数,并获取特定分页。
- 支持参数替换,能够从对象属性中抓取命名参数(named parameters)
- 包括一个消耗资源很少的SQL Builder类
- 部分记录更新
- 包括T4 Templates,可以用于基于数据库结构生成POCO类。
linq2db
linq2db也是一款快速、轻量、类型安全的POCO对象和数据库映射的ORM框架。从构架上来说,linq2db是对比如:Dapper、PetaPoco这个的微ORM的进一步封装,但它不像Entity Framework那样笨重。它没有实现状态跟踪,需要自己处理实体的状态更改等。
EF
ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案。该框架曾经为.NET Framework的一部分,但version 6之后从.NET Framework分离出来。
适合处理大数据。在查询需要多表查询可以选择它,但是它比较笨重。
NHibernate
NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。
特点:
- 开源、免费
- 批量写入
- 批量读/多重查询特性(我理解是在说Future?)
- 批量的集合加载
- 带有lazy="extra"的集合
- 集合过滤器和分页集合
- 二级缓存(实际上NH的二级缓存貌似也很简单?)
- 集成和扩展性
- 代码自动生成,减少代码和sql的开发量,使开发人员摆脱开sql,ado.net和事务,缓存等底层
Dapper
Dapper是一个轻量级的O/R框架,性能强劲,支持原生sql与模型对象混合写法,并且是半自动的,通过DapperExtension插件可以实现纯模型的操作(零Sql)语句,但是处理多表联查时性能不如EF,毕竟EF是微软的亲儿子。
特点 :
- 轻量。只有一个文件(SqlMapper.cs),编译完成之后只有120k(好象是变胖了)
- 速度快。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
- 支持多种数据库。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server
- 可以映射一对一,一对多,多对多等多种关系。
- 性能高。通过Emit反射IDataReader的序列队列,来快速的得到和产生对象,性能不错。
- 支持FrameWork2.0,3.0,3.5,4.0,4.5
性能对比
SqlSugar 和 dapper 性能对比
查询一万次数据并带查询条件
多表连接查询一千次无查询条件
查询一万次不带条件
CPU使用情况
多表联查执行一万次(这里就可以看出EF的优势了)
C# 代码性能优化
IEnumerable
list 继承自 IEnumerable 所以可以用父类对象接收子类的数据 看下面代码段A 和代码段B。A段代码多了一个ToList的操作。所以代码段B性能更胜一筹
List<string> fruits = new List<string> {
"apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
//A
List<string> query = fruits.Where(fruit => fruit.Length < 6).ToList();
//B
IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
foreach (string fruit in query)
Console.WriteLine(fruit);
Lazy< T >
Lazy延时加载类, 延时加载(延时实例化或延时初始化)重点是延时,用时加载。意思是对象在使用的时候创建而不是在实例化的的时候才创建。
对于一个引用类型的T运行时要在堆上开辟空间,必然耗时。
Lazy的出现就意味着解决性能,对于创建的对象开销大,而第一次加载并不使用,后期才能用到,体现出了延时性,提高了启动速度。
延时加载主要应用的场景:
- 数据层(ADO.NET或Entity Framework等ORM,Java里面的Hibernate也用到了这种技术)
- 反射(加载assemblier,type,MEF)
- 缓存对象,领域实体
微软官方文档:传送门
// 写一个model
class LargeObject
{
public int InitializedBy {
get {
return initBy; } }
int initBy = 0;
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
// 这里是 lazy<T>的使用
class TestLazy
{
Lazy<LargeObject> lazyLargeObject = null;
public TestLazy()
{
//创建一个延迟加载对象
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
}
public void ReallyLoad()
{
//此时真正加载
lazyLargeObject.Value;
Console.WriteLine("lazy load big object");
//do something
}
}
void Test()
{
TestLazy t = new TestLazy();
t.ReallyLoad(); //这时,真正延迟加载时才会打印"lazy load big object"
}
C#大量数据做聚合的处理方案
不要直接用DataTable做聚合。先用sql语句把数据查询出来然后转为List对象数组然后再去做聚合。或者读取的时候直接用ORM框架读取出来得到对象数据再做聚合。
//用sql语句获取数据然后转为对象数组
public List<model> GetData()
{
List<model> list = new List<model> ();
DataTable ds_rtn;
try{
string sql="select id,par,tem from table where GcFlag=0";
lock(DBLock)
{
ds_rtn=db.ReturnDataTable(sql);
}
for(int i=o;i<ds_rtn.Rows.Count;i++)
{
model m=new model();
m.id=(int)ds_rtn[i]["id"];
m.par=(int)ds_rtn[i]["par"];
m.tem=ds_rtn[i]["tem"].Tostring();
list.add(model);
}
ds_rtn.Dispose();
}Catch(Exception ex)
{
//写日志
}
}
C# 做大量数据导入数据库
使用 SqlBulkCopy
//这是我用到的表
创建DataTable 注意这里的顺序要和数据库中表里键的顺序一致,包括类型也要一致,还有就是表里的每个字段都要有
DataTable InsDt = new DataTable();
InsDt.Columns.Add("id", typeof(int));
InsDt.Columns.Add("skuid", typeof(string));
InsDt.Columns.Add("placepointid", typeof(string));
InsDt.Columns.Add("product_spec_id", typeof(string));
InsDt.Columns.Add("sale_price", typeof(int));
InsDt.Columns.Add("sku_spec_custom_id", typeof(string));
InsDt.Columns.Add("sku_spec_id", typeof(string));
InsDt.Columns.Add("upc", typeof(string));
InsDt.Columns.Add("weight", typeof(int));
InsDt.Columns.Add("Createtime", typeof(DateTime));
//im.sku_spec是数据源
foreach (var item in im.sku_spec)
{
DataRow row = InsDt.NewRow();
row["skuid"] = im.sku_id.ToString();
row["placepointid"] = storeid;
row["product_spec_id"] = item.product_spec_id.ToString();
row["sale_price"] = int.Parse(item.sale_price.ToString());
row["sku_spec_custom_id"] = item.sku_spec_custom_id.ToString();
row["sku_spec_id"] = item.sku_spec_id.ToString();
row["upc"] = item.upc.ToString();
row["weight"] = int.Parse(item.weight.ToString());
row["Createtime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
InsDt.Rows.Add(row);
}
//调用方法 参数一是和表结构一样的DataTable,参数二是数据库中的表的名称
db.BatchInsert(InsDt, "MedicineInfo_ele_Sku");
这里是BatchInsert方法
public static void BatchInsert(DataTable dt, string tableName)
{
string connstr = Properties.Settings.Default.lswxConnectionString;
using (SqlConnection conn = new SqlConnection(connstr))
{
Stopwatch sw = new Stopwatch();
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
bulkCopy.DestinationTableName = tableName;
bulkCopy.BatchSize = dt.Rows.Count;
conn.Open();
sw.Start();
if (dt != null)
{
bulkCopy.WriteToServer(dt);
sw.Stop();
}
conn.Close();
}
}