问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

求教C#处理sql大量数据的高效率方法

发布网友 发布时间:2022-04-11 03:52

我来回答

2个回答

懂视网 时间:2022-04-11 08:13

大量SQL的解决方案——sdmap

最近看到群里面经常讨论大型应用中SQL的管理办法,有人说用EF/EF Core,但很多人不信任它生成SQL的语句;有人说用Dapper,但将SQL写到代码中有些人觉得不合适;有人提出用存储过程,但现在舆论纷纷反对这种做法;有人提出了iBatis.NET,它可以配置确保高灵活性高性能,也提供动态SQL的功能,但已经多年没有维护。

在几年前,我们某项目中就有总共4MB以上的SQL语句文本,我也注意到产品做大后会,一定出现这个问题,所以我就依照MyBatis的核心思想,支持可配置、动态SQL,但去除了臃肿的xml,自己实现了一套简单好用的语法,然后开源了出来,名字就叫sdmap

在我的介绍页面上已经指出,sdmap的如下特性:

  • 非常简单的语法来描述动态SQL
  • 使用了Emit CIL来确保性能;
  • Visual Studio插件支持,实现了代码高亮、代码折叠、快速导航的特性;
  • 支持所有主流数据库,如MySQLSQL ServerSQLite等(只要Dapper能支持);
  • 可以扩展支持非关系型数据库,如Neo4j
  • 单元测试全覆盖。
  • 语法

    如图:
    技术图片

    该语法有如下特点:

  • namespace关键字表达名字空间;
  • sql关键字表示模板语句;
  • #号的特殊语法可以进行一些判断,里面有isEqual<>#isNotEmpty<>等特殊语法;
  • #include<>,可以包含另一个SQL语句;
  • 语句可以嵌套,sql{}中可以包含另一个sql{}
  • 我们可以对比一下iBatis/MyBatis的语法:

    <!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
     <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
     <id column="id" property="id"/>
     <result column="name" property="name"/>
     <result column="funkyNumber" property="funkyNumber"/>
     <result column="roundingMode" property="roundingMode"/>
     </resultMap>
    
     <select id="getUser" resultMap="usermap">
     select * from users
     </select>
     <insert id="insert">
     insert into users (id, name, funkyNumber, roundingMode) values (
      #{id}, #{name}, #{funkyNumber}, #{roundingMode}
     )
     </insert>
    
     <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
     <id column="id" property="id"/>
     <result column="name" property="name"/>
     <result column="funkyNumber" property="funkyNumber"/>
     <result column="roundingMode" property="roundingMode"
      typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
     </resultMap>
     <select id="getUser2" resultMap="usermap2">
     select * from users2
     </select>
     <insert id="insert2">
     insert into users2 (id, name, funkyNumber, roundingMode) values (
      #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
     )
     </insert>
    
    </mapper>

    相比之下,由于XML的存在,MyBatis的语法有更多噪音。

    简单应用

    Hello World

    其实和MyBatis不同,sdmap设计之初就只考虑好好做一个小巧、精致、快速的模板引擎。因此sdmap可以不依赖于任何数据库,只做字符串解析,最简单的代码是:

    // 安装NuGet包:sdmap
    var c = new SdmapCompiler();
    c.AddSourceCode("sql v1 {Hello World}");
    Console.WriteLine(c.Emit("v1", null)); // Hello World

    参数传入

    当然有一些前端输入,这样就需要第二个参数:

    var c = new SdmapCompiler();
    c.AddSourceCode("sql v1 {Hello #prop<Name>!}");
    Console.WriteLine(c.Emit("v1", new { Name = "Hero"})); // Hello Hero!

    注意我使用了一个#prop<>的语法,这是sdmap中调用指令的语句,表示将Name属性按原样显示在此处。

    参数判断

    有些语句需要根据前端的不同而不同,比如典型的“动态SQL”问题,如果前端传了参数,则执行过滤,没有传则不过滤,这样的代码如下:

    var c = new SdmapCompiler();
    c.AddSourceCode(@"
    sql v1 
    {
     SELECT * FROM [Customer] 
     WHERE 1=1 
     #isNotEmpty<Location, sql {AND Location = '#prop<Location>'}
    }");
    Console.WriteLine(c.Emit("v1", new { Id = 1, Location = "长沙"}));
    Console.WriteLine(c.Emit("v1", new { Id = 2, Location = ""}));

    输出结果如下:

     SELECT * FROM [Customer] 
     WHERE 1=1 
     AND Location = '长沙'
    
     SELECT * FROM [Customer] 
     WHERE 1=1 

    可见,关键的那个isNotEmpty<>控制了Location判断的语句。

    扩展:sdmap.ext

    每次使用时,都需要实例化一个SdmapCompiler来加载sdmap语句很麻烦,在项目中,这部分逻辑重用度非常高,因此我写了一个扩展:sdmap.ext,定义了ISdmapEmiter接口,该接口定义如下:

    public interface ISdmapEmiter
    {
     string Emit(string statementId, object parameters);
    }

    相当于最简单的生成器,然后我写了几个内置实现,可以直接从文件系统或者程序集嵌入的资源中读入这些文件:

    public class EmbeddedResourceSqlEmiter : ISdmapEmiter 
    { 
     public static EmbeddedResourceSqlEmiter CreateFrom(Assembly assembly);
     // ...
    }
    
    public class MultipleAssemblyEmbeddedResourceSqlEmiter : ISdmapEmiter
    {
     public static MultipleAssemblyEmbeddedResourceSqlEmiter CreateFrom(params Assembly[] assemblies);
     // ...
    }
    
    public class FileSystemSqlEmiter : ISdmapEmiter
    {
     public static FileSystemSqlEmiter FromSqlDirectory(
      string sqlDirectory,
      bool ensureCompiled = false);
    
     public static FileSystemSqlEmiter FromSqlDirectoryAndWatch(
      string sqlDirectory,
      bool ensureCompiled = false);
     // ...
    }

    那么有人会问,数据库参数化该如何实现呢?

    扩展:sdmap.ext.Dapper

    答案是Dappersdmap访问数据库时,依赖Dapper做参数化。其实很好理解,sdmap只做数据库访问时的SQL模板引擎前端,Dapper做后端(当然不一定非要用Dapper),sdmap只负责生成SQL语句。

    但随着大家使用越来越多,我也注意到确实可以写一些东西,便于大家更好地配合Dapper一起使用。因此我写了另外两个扩展:sdmap.extsdmap.ext.Dapper

    其中sdmap.ext仍然和数据库无关,定义了一些.sdmap文件的读取和自动加载逻辑;sdmap.ext.Dapper依赖于Dapper,定义了一些便利方法:
    技术图片

    如图,用过Dapper的朋友知道,DapperIDbConnection定义了一套扩展方法,这里我也为IDbConnection定义了一套一样的扩展,只要最后加了ByMap后缀,第二个参数都为sqlMapName,与其传入原始的SQL语句,此处将传入定义在.sdmap文件中的配置,如原先使用Dapper的朋友,代码可能这样写:

    var data = _db.Query<Customer>("SELECT * FROM [Customer] Where Id = @Id");

    换成sdmap后,代码应该是这样写:

    var data = _db.QueryByMap<Customer>("Customers.GetById");

    然后sdmap配置如下:

    namespace Customers
    {
     sql GetById
     {
     SELECT * FROM [Customer] WHERE Id = @Id
     }
    }

    注意,sdmap使用了Dapper的参数化方式,只需在SQL中写@Id这样的语句,即可自动实现参数化,得出结果完全一样,并且SQL不存在注入问题,代码中不包含SQL语句,语句都写在配置文件中。

    数组参数化

    由于Dapper的存在,sdmap相当于也自动支持了数组的参数化,只要像Dapper那样写IN即可:

    namespace Customer
    {
     sql GetByIds
     {
     SELECT * FROM [Customer] WHERE Id IN @Ids
     }
    }

    相关链接

    Github地址

    https://github.com/sdcb/sdmap
    我的Github首页还包含了使用sdmap.ext.Dapper的一步一步使用教程,可以依照上面的使用。

    文档地址

    https://github.com/sdcb/sdmap/wiki

    所有指令参考链接:

    https://github.com/sdcb/sdmap/wiki/Common-macros

    NuGet包地址

  • https://www.nuget.org/packages/sdmap
  • https://www.nuget.org/packages/sdmap.ext
  • https://www.nuget.org/packages/sdmap.ext.Dapper
  • Visual Studio插件地址

    https://marketplace.visualstudio.com/items?itemName=sdmapvstool.sdmapvstool

    VS插件提供了.sdmap文件代码高亮、自动定位、代码折叠的功能,可以不装,但不装就没这些体验。

    总结

    我写sdmap最初纯粹是因为想挑战自己,它包含了【编译器前端——ANTLR】、【编译器后端——CIL】、【Visual Studio插件如何制作】、单元测试、文档等主题。

    但后来随着这个项目的发展,越来越多的朋友用了起来。用过的都纷纷提出了自己的想法,然后做了许多润色,解决了不少局限性,但我从未做过推广——这是我第一次将这个项目用文字的形式发表出来。希望这个项目能给大家以管理大量SQL的启发。

    上文中提到了许多有意思的主题,2020年到了,我有空就会一一介绍这些主题,都非常有意思,最重要的是,其实都很好学??。喜欢的朋友请关注我的微信公众号:【DotNet骚操作】

    技术图片

    大量SQL的解决方案——sdmap

    标签:edr   stat   tip   想法   定位   packages   hub   解析   OLE   

    热心网友 时间:2022-04-11 05:21

    我来扔个砖,希望能引出玉来。我只是说一下大量数据查询的问题。

    1、你要给表建立索引,这很重要。让你们的DBA优化。

    2、有些表结构可能要优化。特别是联表查太多的情况,子查太多的情况,会非常烦人。

    3、可以考虑用多线程,把表加载到内存中来操作。写段伪代码,望高手能出来指点更多。

    //你的主调用线程。我就用控制台了
    Main()
    {
       //10万一查
       string str1 = @"select ....  from xxx where id >1 and and id < 100000";
       string str2 = @"select ....  from xxx where id >100000 and and id < 200000";
       Task.Factory.StartNew(new Action(() =>
        {
            ThreadQuery(str1);
        }));
        Task.Factory.StartNew(new Action(() =>
        {
            ThreadQuery(str2);
        }));
    }

    然后你就写个ThreadQuery()方法来查询sql

    void ThreadQuery(string str)
    {
        //sql的查询操作,代码网上好多
        //查出来的结果,你随便放在内存对象里。
    }

    求教C#处理sql大量数据的高效率方法

    1、你要给表建立索引,这很重要。让你们的DBA优化。2、有些表结构可能要优化。特别是联表查太多的情况,子查太多的情况,会非常烦人。3、可以考虑用多线程,把表加载到内存中来操作。写段伪代码,望高手能出来指点更多。//你的主调用线程。我就用控制台了Main(){ //10万一查 string str1...

    C# 在调用大量数据时怎么优化好,一次调用十万以上的数据记录?

    1、数据库优化方法:使用存储过程、索引 2、如果是winfrom 可以使用异步读取数据控件backgroundWorker1,可以避免界面出现假死状态 3、如果是ASP.NET,可以使用JQUERY异步加载

    c#中往mysql里批量插入上万条数据,有比较高效的方法吗

    引用MySql.Data.dll , 调用MysqlBulkCopy函数即可。这个函数在处理海量数据插入的时候效率尤为明显, 小量数据反而没什么优势,而且由于传入的DataTable格式必须和表的字段一模一样(空的列也要传进去),导致C#要写很多代码来构造这个数组,所以要你自己权衡用还是不用。我在自己的电脑上批量插入一亿条数...

    C#如何在海量数据下的高效读取写入MySQL

    】使用原生的Connection、Command。 然后写原生的SQL语句。分析:【重武器】在我们这里肯定直接被PASS, 他们应该被用在大型项目中。 【轻武器】Dapper,PetaPoco 看过源码你会发现用到了反射,虽然使用IL和缓存技术,但是还是会影响读取效率,PASS好吧那就只有使用匕首,原生SQL走起,...

    C#中若要频繁的读写和查询SQL数据库有什么方法或者方案?

    在没有修改的前提下读取的话。可以将数据读出来放入缓存。频繁写入的话。可以将语句多条语句拼接。一个性传入数据库。多条语句执行的话。显示开启数据库事务。这样效率会高点。

    C#循环计算出数据写入文本或数据库时如何提高效率?

    利用SqlBulkCopy进行批量写入,大数据量效果明显。

    SQL语句太长,在C#中执行失败,该怎么解决

    一般一次性执行的数据量如果太大(我在自己库里试过的最大单行条数是1000)数据库会直接崩溃的。所以对于这种情况。我的做法是:使用循环清空字符串,然后再单条执行。不要想着一下子把拼接好的字符串抛给数据库。那样的话开始不蹦,数据大了早晚崩溃的。

    c#向数据库插入大量数据时如何解决速度慢的问题

    批量导入数据,切记用循环去逐条插入,这样即使再快,上万条十万条也就速度很慢了

    求c#语言下千万级数据检索的有效方案

    需要使用服务器集群,并且把所需数据尽量放置到内存中来。最好的解决方案是采购MY SQL集群,每台服务器内存8G以上(这不算奢侈的配置),这样在几十台服务器以上之后就可以响应了。当然更全面的还需要考虑中国的国情,注意网通与电信之间的瓶颈问题的处理。希望能帮到你。

    用C#连接数据库SQL并进行读取时,因数据量过大导致运行极慢,想建一...

    在datatable里算,具体的操作你看下c#关于datatable的操作,这样就不会大量占用数据库时间,但这样又会占用大量内存,根据你的需要试试看吧。在内存里计算不在sql里面快,只是你在添加数据库时需要向datatable和sql里面同时添加同一条数据。10几万的数据我都是这么操作的。

    sqlserver大数据处理 sql大数据处理 sql2008大数据处理 大数据sql如何抽取数据 sparksql处理千万数据 sqlserver大数据量 sql数据处理 sparksql删除数据sql sqlserver大数据
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    黄山区中通快递派件时间 今天早上五点的中通快递从合肥中转部运往黄山市最快什么时候到达目的地... 从郑州往安徽黄山要寄一件衣服,用什么方式好呢?还有就是如果用快递的... 从徐州出发2天一夜自驾游哪里好_徐州周边2日自驾游!合适的推荐下_百度... 喝茶时加糖有助缓解工作压力 喝茶 可以放糖吗? 喝茶时到底能不能在茶里面加“糖”? 喝茶加糖不营养?茶应该这么喝 solidworks flow simulation 问题,请各位大侠解答,谢谢! 三十首正能量歌曲有哪些 把别人做爱语音发给她老公 我算不算侵犯别人隐私权? 女朋友确定已经出轨了,她新欢小三竟然和我语音了,怎么办,我气死了,今天她新欢竟然登录她微信 以前在一起的时候爱爱他很温柔吵了几次架以后他爱爱非常粗鲁,就算我和他说了,他也不会温柔,为什么 女友月经没完,就*了,这样做对女生和男生身体上都有什么伤害,这样做容易得什么病吗 这段时间,经常跟男朋友爱爱,然后我就发现憋不住尿了,跟这个有关系嘛 男友天天要我语音跟他说晚安,不然他说他睡不着,有一次没说都不行,为什么? 语音爱爱用什么字母代替? 对于大量的sql语句大家是怎么管理的 我老公经常上网还在网上和别人语音*我怎么和他吵他都不改我该怎么办 爱爱qq号码 男士语音我打字 我爱上了一个网友,因为爱又不想现实背叛老公,偶然的机会和他语音*了,我也非常喜欢这种*方法了 移动手机想弄些个性化彩铃怎么搞? 怎样把手机百度网盘里的视频资料上传到电脑上? 血糖高应该注意什么? 高血糖预防要注意些什么 血糖高的人饮食上需要注意什么呢? 血糖高有什么症状?需要注意什么? beatsX遇到神奇问题,开机很随缘有时能开,有时要换个姿势才能开,但越这样下去开机越困难 血糖高需要注意些什么?哪些东西能吃?哪些东西不能吃?详细点谢谢! 血糖高,在饮食方面应该注意些什么 sql语句in 后面跟的数据过多怎么解决 求异世界的美食家全文百度云链接,谢谢 异世界的美食家几个女主 异世界的美食家_by李鸿天_txt全文阅读,百度网盘免费下载 异世界的美食家狗爷是什么境界 异世界的美食家的百度网盘谁有 《异世界的美食家》主要讲述了什么内容? 异世界的美食家小幽是谁 为什么《异世界的美食家》如此受欢迎? 《异世界的美食家》有什么精彩桥段? 哪个英语网站比较好 为什么《异世界的美食家》如此受欢迎 异世界的美食家是耽美吗?还是言情? 异世厨神人物介绍? 找一本类似于异世界的美食家的小说。主角也是在异世界有一个厨神系统还有一只猫宠叫小白 异世界的美食家 有女人和男主在一起的吗? 求类似于异世界的美食家的小说 九寨沟旅游需要爬山吗 旅游去九寨沟好玩吗?会不会很累? 九寨沟旅游咨询