SQL 嵌套 N 层太长太难写怎么办?

我们工作中写SQL处理数据是家常便饭,不管是应用内数据处理还是临时查询分析都可以用SQL完成,相对其他技术(如Java等高级语言)也更简单。不过,SQL的简单只限于简单需求,有些复杂计算场景SQL写起来却很难,嵌套N层以至于达到几百上千行,说SQL代码长度时通常不会以行计而是以KB计。这种情况并不少见,相信经常写SQL的小伙伴并不陌生。

为什么会出现这种情况呢?在http://c.raqsoft.com.cn/article/1639032922105 里详细分析了这个问题。虽然SQL比其他数据处理技术更简单,但仍存在一些短板(如缺乏有序支持、集合化不彻底、没有高级语言的对象引用机制等),导致复杂计算用SQL表达出来很繁琐。这种既复杂又很长的SQL会带来很多问题。

长SQL有什么危害?

复杂长SQL给我们带来的第一个困扰是难写。

其实,代码长本身还不是大问题,很多任务步骤多也就会写得长,但并不难。而SQL的长,常常是伴随着难,而且会随着长度增加变得异常难。SQL在解题时很绕(思维方式上的难),你没法按照正常思路去实施算法,明明想出一个好的解法,简单一二三四步就完成了,但用SQL就要绕来绕去,不嵌套几层写个几十上百行好像体现不出你水平一样。而且不光嵌套子查询,复杂SQL还伴随多表关联和各种过滤条件,写的时候要保持头脑异常清醒,一旦写错不仅很难定位,有时还会把数据库跑死。这当然跟SQL不提倡过程(CTE语法提供了一定支持)有关,一个任务写100行代码,分成 100 个语句还是只有 1 个语句,其复杂度完全不是一个层面的。

另外,写代码还离不开调试,而SQL的调试功能可谓难用至极。直到今天各大数据库都没提供像样的调试功能,相比其他高级语言的开发调试环境简直不忍直视。一句嵌套N层的长SQL发现写的不对只能把子查询从长语句里一层一层摘出来单独执行调试定位,费时费力,这更增大了SQL的书写难度。

难写就意味着开发周期长,我们写SQL都是为前端业务服务的,一个计算需求连写带调试搞个三五天甚至一周,恐怕业务时效性都没了,被怒怼也是有苦难言。

除了难写,复杂SQL还很难维护。数据处理业务的稳定性往往很差,经常要修改,不过想要修改这些SQL恐怕并非易事。别说新人接手,就是作者本人也经常出现过一段时间自己都看不懂的尴尬情况。改一个SQL跟重新写一个的时间差不多,这还玩啥。

另外复杂SQL还会影响数据库移植。虽然数据库移植不经常发生,不过一旦发生就要命。近些年随着业务的高速发展以及开源数据库的崛起,更换数据库时有发生。这就涉及到SQL迁移,我们知道数据库都是有方言的,在一个数据库上使用的函数到另外一个数据库未必管用,而且各类数据库对SQL标准的支持程度不同(如Oracle窗口函数支持的很好,其他数据库就要差很多),这些“特殊的”内容夹杂在复杂SQL里就很难实现数据库迁移了。

不管怎样,复杂SQL都是数据开发人员的噩梦。

怎么办?

SQL难的问题可不是第一天出现,大家也都在积极寻找解决办法。其实现在很多开发方法已经不再推荐写复杂SQL,像ORM技术算是革掉SQL半条命,而微服务等框架更是要求SQL仅仅用于完成基本的数据读写,而不能用于做复杂计算和业务处理。这些方法的思路很清晰,即把SQL的应用局限于基本的读写任务,在应用端完成复杂的数据处理和业务逻辑,这样就可以规避SQL的那些问题,架构上也更符合现代应用的需要。

不用SQL,那些复杂的计算和业务逻辑该用什么技术来做呢?

当然只能是其它程序语言了,几乎所有应用级程序语言都可以指挥SQL工作,实现这种开发架构不是问题。那么,这个问题是不是就被轻易解决了?

我们来考察一下这些常用的技术。

Java

Java肯定是第一选择,毕竟众多应用程序都是Java开发的,如果能搞定这些数据处理就会有很多优势。Java天然支持过程计算,实现复杂计算时虽然代码可能更长,但可以按照正常思维实现算法,这样是不是就可以替代SQL了?

No,没有这么简单。

由于Java缺乏专业的结构化数据对象,缺少来自底层的有力支持,在实现SQL这类的复杂计算时并不容易。

结构化数据计算的返回值的结构随计算过程而变,大量的中间结果同样是动态结构,这些都难以事先定义,而Java是强类型语言,又必须事先定义数据对象的结构(否则只能用map这类操作繁琐的数据对象),这就使Java的结构化计算僵化死板,lambda语法的能力严重受限。解释性语言可以简化参数的定义,函数本身就可指定参数表达式应解释成值参数还是函数参数,而Java是编译型语言,难以区分不同类型的参数,必须设计复杂的接口才能实现匿名函数(主要指lambda语法),这连SQL程序员都不易掌握。省略数据对象而直接引用字段(比如写成"单价*数量"),可显著简化结构化数据计算,但Java缺乏专业的结构化数据对象,目前还无法支持此类表面简单实则巧妙的语法,这就使Java代码冗长且不直观(只能写成"x.单价*x.数量")。

缺少结构化数据计算类库还会导致代码过长,同样的一个分组汇总用SQL一句就能写出来改成Java就要写几十行,这显然也对简化复杂SQL无益。这个问题即使在Java8增加了Stream后也没有明显改善,为了简化运算用Java取代SQL基本不可能(有些应用用Java做数据处理往往是由于架构上的要求,就其简便性上还远不及SQL)。

另外,Java作为编译型语言很难热部署,也就难以及时应对多变的数据计算场景。

Python

直接的Java不行,那大热的Python怎么样呢?Python+SQL可比Java+SQL容易得多了吧。

的确,Python(主要是Pandas)提供了丰富结构化计算类库,计算实现要比 Java 简单很多。不过,实际使用Pandas处理数据尤其是复杂运算时也会碰到代码很难写的情况。其实,Pandas 本来就不是为结构化数据设计的,它并不是我们熟悉的数据表(一行行数据记录的集合),而是个矩阵。用来处理结构化数据时,做些过滤合并这些简单运算还好点,碰到分组有序等复杂一些运算,就会比较麻烦了,思路上也经常要绕一下。

这还不是Python的主要问题,Python与应用结合的难点在于其集成性上。

Python很难与Java应用集成!

Python和Java集成主要有两种方式。一种是服务式调用,既然Python和Java是两套体系,那就单独部署通过服务(网络通信)的方式交互,这种方式要维护两套应用比较麻烦,还会存在一些安全认证系统权限等管理问题,而且数据交换的性能也很差,不到万不得已不会采用这种方式。另一种是使用Jython这种解释器(JVM上的Python),由于采用Java开发可以很方便与应用集成,但Jython又缺乏足够的计算库(如Pandas)很难应付那些复杂计算。无论采用何种方式,都会在应用方面产生巨大限制,导致在Java应用中用Python来实现复杂计算的可行性不高。

除非你把整个应用都用Python写,但是Java的各种企业级能力又用不上了,做做小应用还行吧。

Scala

Scala的特性与Python类似,都提供了DataFrame对象,实现简单的结构化数据计算也比较简单,作为高级语言有序、对象属性化等特性支持良好,相对Java在集合运算上也更简单。Scala运行于JVM之上,天生就容易被JAVA集成,这些都是Scala的优点。

Scala的缺点在于使用难度较大,难学更难精,用于复杂数据处理与SQL相比尤有劣势,也就不用想通过Scala简化复杂SQL了。这大概也是为什么Spark要回归SQL的原因了吧。而且,Scala作为编译型语言同样不支持热部署。

SPL

这些高级语言都存在这样那样的缺点,从简化复杂SQL的角度来看无一能胜任。那还有什么办法呢?

其实,从前面的分析中我们明显能够感受到,面向结构化数据计算尤其是复杂计算,现有技术(开发语言)都各有优缺点,SQL擅长复杂计算但对有序、过程支持不好,Java恰好反过来支持有序和过程但集合计算能力很弱。如果能综合这些技术的优点,那简化复杂SQL的目标也就达成了。

开源SPL恰好是这样一个产品。

SPL全称Structured Process Language,是一个专门用于结构化数据计算的程序语言。

常规计算能力

一致的数据类型

SPL相对Java提供了更专业的结构化数据类型,即序表。和SQL的数据表一样,序表是批量记录组成的集合,具有结构化数据类型的一般功能,可以与SQL无缝交互承接SQL的返回值。

序表支持所有的结构化计算函数,计算结果也同样是序表,而不是Map之类的数据类型。比如对分组汇总的结果,继续进行结构化数据处理。

Orders.groups(year(OrderDate):y; sum(Amount):m).new(y:OrderYear, m*0.2:discount)

丰富的计算类库

在序表的基础上,SPL提供了丰富的结构化数据计算函数,比如过滤、排序、分组、去重、改名、计算列、关联、子查询、集合计算、有序计算等。这些函数具有强大的计算能力,无须硬编码辅助,就能独立完成计算。

如组合查询:

Orders.select(Amount>1000 && Amount<=3000 && like(Client,"\*bro\*"))

内关联:

join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))

SPL支持简单形式的Lambda语法,无须定义函数名和函数体,可以直接用表达式当作函数的参数。修改业务逻辑时,也不用重构函数,只须简单修改表达式。SPL是解释型语言,使用参数表达式时不必明确定义参数类型,使Lambda接口更简单。比如计算平方和,想在sum的过程中算平方,可以直观写作:Orders.sum(Amount*Amount)。

同时作为解释执行语言的SPL还天然支持动态数据结构,可以根据计算结果结构动态生成新序表,特别适合计算列、分组汇总、关联这类计算。较复杂的计算通常都要拆成多个步骤,每个中间结果的数据结构几乎都不同。SPL支持动态数据结构,不必先定义这些中间结果的结构。比如,根据某年的客户回款记录表,计算每个月的回款额都在前10名的客户。

Sales2021.group(month(sellDate)).(~.groups(Client;sum(Amount):sumValue)).(~.sort(-sumValue)).(~.select(#<=10)).(~.(Client)).isect()

过程控制与SQL协同

除了提供与SQL相当的集合运算能力,SPL还对过程控制和分步计算提供了良好支持,灵活的分支判断语句、循环语句,配合专业的结构化数据对象,可以方便地实现各类业务逻辑。比如找出销售额累计占到一半的前n个大客户,可以这样分步实现:

A
1 =db.query(“select client,sum(amount) amount from sales group by client order by amount desc”)
2 =A1. sum(amount)/2
3 =0
4 =A1.pselect((A3=A3+amount,A3>=A2))
5 =A1(to(A4))

通过SQL先完成分组汇总并按汇总值降序排序,然后SPL承接SQL的计算结果再通过分步方式完成后续计算,SPL与SQL有效结合,这样就很大程度达到了简化复杂计算的目标。

在应用中,SPL很多时候都要与SQL交互协同,充分发挥二者的优势,包括数据库读写、事务处理、流程处理、存储过程调用等。

数据库写入(更新/插入):

db.update@u(A7,sales;ORDERID)

执行DML语句:

db.execute("insert into DEPARTMENT(DEPT, MANAGER) values(?,?)","TecSupport",9)

调用存储过程:

db.proc({db_proc(?,?),,:101:"o":table1,1:0:"i": })

丰富的集合运算能力加上过程计算与流程控制(包括指挥SQL),这样就获得了SQL和Java相当的能力,而实现上要比Java更简单。

超越SQL的能力

SPL不仅覆盖了SQL的所有计算能力,还提供了更强大语言功能。基于这些特性可以很方便原来在SQL中不易完成的运算,简化复杂计算可不是开玩笑的。

离散性及其支持下的更彻底的集合化

集合化是SQL的基本特性,即支持数据以集合的形式参与运算。但SQL的离散性很不好,所有集合成员必须作为一个整体参于运算,不能游离在集合之外。而Java等高级语言则支持很好的离散性,数组成员可以单独运算。但是,更彻底的集合化需要离散性来支持,集合成员可以游离在集合之外,并与其它数据随意构成新的集合参与运算 。

SPL兼具了SQL的集合化和Java的离散性,从而可以实现更彻底的集合化。

SPL很容易表达“集合的集合”,适合分组后计算。比如,找到各科成绩均在前10名的学生:

A
1 =db.query(“select * from score”) .group(subject)
2 =A2.(~.rank(score).pselect@a(~<=10))
3 =A1.(~(A3(#)).(name)).isect()

有序支持

有序计算是离散性和集合化的典型结合产物,成员的次序在集合中才有意义,这要求集合化,有序计算时又要将每个成员与相邻成员区分开,会强调离散性。SPL兼具集合化和离散性,天然支持有序计算。

具体来说,SPL可以按绝对位置引用成员,比如,取第3条订单可以写成Orders(3),取第1、3、5条记录可以写成Orders([1,3,5])。

SPL也可以按相对位置引用成员,比如,计算每条记录相对于上一条记录的金额增长率:

Orders.derive(amount/amount[-1]-1)

SPL还可以用#代表当前记录的序号,比如把员工按序号分成两组,奇数序号一组,偶数序号一组:

Employees.group(#%2==1)

在有序计算的支持下,再处理结构化数据计算中关于次序的运算(诸如比上月、比去年同期、前 20%、排名等)就很方便了。

对象引用

SPL序表的字段可以存储记录或记录集合,这样可以用对象引用的方式,直观地表达关联关系,即使关系再多,也能直观地表达。比如,根据员工表找到女经理下属的男员工:

Employees.select(gender:"male",department.manager.gender:"female")

更方便的函数语法

提供大量功能强大的结构化数据计算函数本来是一件好事,但这会让相似功能的函数不容易区分,无形中提高了学习难度。

SPL提供了特有的函数选项语法,功能相似的函数可以共用一个函数名,只用函数选项区分差别。比如select函数的基本功能是过滤,如果只过滤出符合条件的第1条记录,可以使用选项@1:

Orders.select@1(Amount>1000)

数据量较大时,用并行计算提高性能,只须改为选项@m:

Orders.select@m(Amount>1000)

对排序过的数据,用二分法进行快速过滤,可用@b:

Orders.select@b(Amount>1000)

函数选项还可以组合搭配,比如:

Orders.select@1b(Amount>1000)

结构化运算函数的参数常常很复杂,比如SQL就需要用各种关键字把一条语句的参数分隔成多个组,但这会动用很多关键字,也使语句结构不统一。SPL支持层次参数,通过分号、逗号、冒号自高而低将参数分为三层,用通用的方式简化复杂参数的表达:

join(Orders:o,SellerId ; Employees:e,EId)

方便的编辑调试功能

与SQL难用的编辑调试功能不同,SPL提供了简洁易用的开发环境,单步执行、设置断点,所见即所得的结果预览窗口…,使得开发调试效率更高。

SPL采用了网格式编码方式,代码不仅天然对齐层次清晰,在实施过程计算时可以直接使用格子名称来引用上一步的计算结果而不必费心定义变量(虽然也支持)非常方便。好用的开发环境自然起到事半功倍的效果,进一步简化复杂计算实施难度。

应用集成、低耦合与热切换

SPL提供了标准应用接口(JDBC/ODBC/RESTful)可以很方便与应用集成。尤其对于Java应用可以将SPL作为嵌入引擎集成,使得应用本身就具备强数据计算能力。

JDBC调用SPL 代码示例:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
Statement st = connection.();
CallableStatement st = conn.prepareCall("{call splscript(?, ?)}");
st.setObject(1, 3000);
st.setObject(2, 5000);
ResultSet result=st.execute();

同时,SPL采用解释执行机制,天然支持热切换。这样对于稳定性差、经常需要新增修改的数据处理需求非常友好。SPL脚本可以与Java程序独立,外置在Java之外,修改和维护都可以独立进行,脚本修改上传后就能实时生效,保证应用可以不中断地提供数据服务。

SPL外置算法不仅能有效降低应用与数据库的耦合性,独立的SPL模块还可以进一步降低应用各个模块间的耦合性,使得结构更为清晰,架构也更为合理。

总结一下,SPL之所以更简单是因为SPL相当于结合了SQL和其他高级语言(如Java)的优点,并在此基础上增加了诸多特性让复杂计算不再难写,同时可以与应用完美结合使得应用架构更为合理。有了SPL的帮助,我们相信,未来的某一天上千行的复杂SQL将不复存在。

SPL资料

  • SPL下载
  • SPL源代码
关注下面二维码,订阅更多精彩内容。
微信打赏
关注公众号(加好友):


作者: 王磊的博客
出处: http://vipstone.cnblogs.com/

本文转载于网络 如有侵权请联系删除

相关文章

  • JDK10新特性

    JDK10新特性局部变量类型推断引入并行Full应用程序类数据共享线程本地握手在备用存储装置上进行堆内存分配基于Java的实验性JIT编译器删除javah工具JDK10新增APItransferTo方法复制文件IO流大家族添加Charset参数的方法ByteArrayOutputStream新增toString方法局部变量类型推断JDK10可以使用var进行局部变量类型推断。varstr="abc";//推断为字符串类型 varl=10L;//推断为long类型 varflag=true;//推断为boolean类型 varlist=newArrayList<String>();//推断为ArrayList<String> varstream=list.stream();//推断为Stream<String>复制局部变量类型推断使用场景如下:局部变量循环内publicclassdemo01var{ //varx=10;//成员变量不能使用var publicstaticvoidmain(String[]args){ vara=1;

  • JQuery扩展插件Validate—5添加自定义验证方法

    从前面的示例中不难看出validate中自带的验证方法足以满足一般的要求,对于特别的要求可以使用addMethod(name,method,message)添加自定义的验证规则,下面的示例中添加了一个用于正则表达式验证的扩展验证的方法,示例如下:<script type="text/javascript">         jQuery.validator.addMethod("regex",  //addMethod第1个参数:方法名称         function(value, element, params) {     //addMethod第2个参数:验证方法,参数(被验证元素的值,被验证元素,参数)             var exp = new RegExp(params);     //实例化正则对象,参数为传入的正则表达式             return exp.test(value);                    //测试是否匹配         },         "格式错误&

  • CVPR 2021 Image Matching 挑战赛双冠算法:揭秘AR导航背后的技术

    在刚刚结束的CVPR2021ImageMatching比赛中,旷视研究院3D组取得了两冠一亚的成绩。ImageMatching(图像匹配)是计算机视觉领域最基础的技术之一,它是指通过稀疏或者稠密特征匹配的方式,将两幅图像相同位置的局部信息进行关联。ImageMatching在很多领域均有广泛应用,如机器人、无人车、AR/VR、图像/商品检索、指纹识别等。本文将详细介绍旷视的比赛方案、实验和一些思考。滑动查看更多图片一、比赛介绍图像匹配是指将两幅图像具有相同或者相似属性的内容或结构进行像素上的识别与对齐。一般而言,待匹配的图像通常取自相同或相似的场景或目标,或者具有相同形状或语义信息的其他类型的图像对,从而具有一定的可匹配性。 ImageMatchingChallenge本次ImageMatchingChallenge(IMC)比赛分为两个赛道——unlimitedkeypoints和restrictedkeypoints,即每张图片可提取特征点数量分别小于8k和2k。比赛分为三个数据集——Phototourism、PragueParks和GoogleUrban。这三个数据集差异化较大,

  • 计算机视觉:学术界与工业界GAP有多大?

    近年来,随着以深度学习为代表的机器学习方法在计算机视觉领域的广泛应用,以及计算机视觉在工业界场景中不断落地,CV领域的产、学两界之间的界限逐渐模糊,高校师生大规模加入工业界探索,而工业界也投入大量资本进行学术研究。这就导致一个“奇怪”的现象,在学术顶会中,常常会看到,一篇学术论文的研究者,既有高校师生,又有企业研发团队,似乎基础研究和商业已经实现了无缝衔接。站在2020年下半年,在计算机视觉领域,学术界和工业界是否还存在GAP呢?CV领域研究生如何成功顺利跨入企业,成为优秀人才?企业的顶会参与越来越多,难道他们真的在乎研究?计算机视觉研究的未来趋势有哪些?针对这些问题,在由中国图象图形学学会主办、视觉大数据专委会承办,北京智源人工智能研究院和美团协办的ECCV2020中国预会议上,华刚(WormpexAIResearch副总裁兼首席科学家)、田奇(华为诺亚方舟计算机视觉首席科学家)、王井东(微软亚洲研究院)、魏晓林(美团视觉智能中心负责人)、熊红凯(上海交通大学教授)等学术界和工业界CV学者进行了一次深入探讨,圆桌主席由董晶(中科院自动化所副研究员)担任。左列由上至下为董晶、田奇、熊红

  • k8s-apiserver工作原理

    APIServerkube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能提供集群管理的RESTAPI接口,包括认证授权、数据校验以及集群状态变更等提供其他模块之间的数据交互和通信的枢纽(其他模块通过APIServer查询或修改数据,只有APIServer才直接操作etcd)工作原理kube-apiserver提供了Kubernetes的RESTAPI,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过etcd)。API访问有多种方式可以访问Kubernetes提供的RESTAPI:1、kubectl命令行工具 2、SDK,支持多种语言 Go Python Javascript Java CSharp 3、其他OpenAPI支持的语言,可以通过gen工具生成相应的client 复制kubectlkubectlget--raw/api/v1/namespaces kubectlget--raw/apis/metrics.k8s.io/v1beta1/nodes kubectlget--raw/apis/metrics.k8s.i

  • 2018-10-12-如何解决python找不到Crypto模块

    涉及加密算法的python代码,尤其是git上down下来的“老代码”经常会遇到神奇的报错ImportError:NomodulenamedCrypto.Cipher,这个问题谷歌上也是哀鸿遍野,简单描述下可能遇到的坑,以及解决方案首先一般正常人想到的是没有使用pip安装一个pipinstallCrypto 复制于是你得到了一个叫做crypto1.4.1的package,它的github是这样的而真正的所需的项目叫做pycrypto2.6.1,它的github是这样的注:这里没有对crypto项目有任何的不敬,只是目前pypi中两个项目的名称对大量开发者造成困扰然而坑还没有结束,使用pip安装pycrypto依然会报错(至少在windows上如此)pipinstallpycrypto 复制原因是编译环境缺少#include<stdint.h>,需要手动设置vc编译器的环境变量(以下步骤需要你安装了visualstudio)管理员权限开启cmd运行visualstudio中的vsvars.bat(找不到?试试wox,我的是”D:\ProgramFiles(x86)\Micro

  • Yii2.0 RESTful API 基础配置教程

    这篇说下yii2.0开发API吧,使用RESTfulAPI模式安装Yii2.0通过Composer安装这是安装Yii2.0的首选方法。如果你还没有安装Composer,你可以按照这里的说明进行安装。安装完Composer,运行下面的命令来安装ComposerAsset插件:phpcomposer.pharglobalrequire"fxp/composer-asset-plugin:^1.2.0"复制安装高级的应用程序模板,运行下面的命令:phpcomposer.pharcreate-projectyiisoft/yii2-app-advancedadvanced2.0.13复制初始化高级模板cdadvanced init复制修改数据库连接属性打开common\config\main-local.php,配置数据库连接信息'db'=>[ 'class'=>'yii\db\Connection', 'dsn'=>'mysql:host=127.0.0.1;dbn

  • IaaS的演进!三句话九张图摸底裸金属和容器即服务

    近两年来,只要是与IaaS(基础设施即服务)相关,不论是共襄盛举的业界峰会,还是个别云服务提供商的新品发布,“裸金属即服务”和“容器即服务”都会被频频提及,风头十足! 为什么它们会如此受人关注?一句话:因为它们有望破解现有的、基于虚拟机的云基础设施服务面临的两大挑战,即:传统企业使用公有云,特别是运行关键业务负载时,遇到的资源扩展和适配上的限制,对数据安全的顾虑,以及在性能输出上难以避开的虚拟化层的损耗。 需要频繁升级迭代在线应用和服务的互联网企业,难以在基于虚拟机的基础设施上实现高效DevOps所需的更优灵活度和更细的应用颗粒度,应用的移植也不够方便。 那么,裸金属和容器即服务究竟有哪些独到优势,可用于解决上述难题呢?又是一句话:裸金属即服务,目标是尽可能提供原生级别的性能和安全性;而容器即服务,则是云原生(CloudNative)架构的关键承载技术。具体来说:裸金属的“裸”字,是其精髓所在。这要求它提供物理机级别的性能和安全隔离,“即服务”则意味着它还能实现物理机体验与基于云的资源管理和调配能力的融合。云服务提供商可在其上,为企业用户提供在公有云基础设施上构建其私有云或专属云的服务

  • SQL中GROUP BY用法示例

    概述GROUPBY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUPBY比较类似Excel里面的透视表。 GROUPBY必须得配合聚合函数来用,分组之后你可以计数(COUNT),求和(SUM),求平均数(AVG)等。常用聚合函数count()计数sum()求和avg()平均数max()最大值min()最小值语法SELECTcolumn_name,aggregate_function(column_name) FROMtable_name WHEREcolumn_nameoperatorvalue GROUPBYcolumn_name;复制例子接下来我们将通过例子进行理解: 我们现在有一张dept_emp表共四个字段,分别是emp_no(员工编号),dept_no(部门编号),from_date(起始时间),to_date(结束时间),记录了员工在某一部门所处时间段,to_date等于9999-01-01的表示目前还在职。image.png部门人数我们现在想知道每个部门有多少名在职员工,步骤如下:筛选在职员

  • 前端必备的 HTTP 知识!看这篇就够了!!

    HTTP起源HTTP是由蒂姆·伯纳斯-李(TimBerners—Lee)于1989年在欧洲核子研究组织(CERN)所发起其中最著名的是1999年6月公布的RFC2616[1],定义了HTTP协议中现今广泛使用的一个版本——HTTP1.1HTTP是什么全称:超文本传输协议(HyperTextTransferProtocol)概念:HTTP是一种能够获取像HTML、图片等网络资源的通讯协议(protocol)。它是在web上进行数据交换的基础,是一种client-server协议HTTP——因特网的多媒体信使——《HTTP权威指南》。HTTP在因特网的角色:充当一个信使的角色,干的就是一个跑腿的活,在客户端和服务端之间传递信息,但我们又不能缺少它。HTTP协议是应用层的协议,是与前端开发最息息相关的协议。平时我们遇到的HTTP请求、HTTP缓存、Cookies、跨域等其实都跟HTTP息息相关HTTP的基础特性可拓展协议。HTTP1.0出现的HTTPheaders让协议拓展变得更加的容易。只要服务端和客户端就headers达成语义一致,新功能就可以被轻松的加入进来HTTP是无状态的、有会话的

  • C primer plus笔记之初识C语言

    初识C语言--本文参考书籍:       StephenPrata的《CPrimerPlus》前言C语言是一门抽象的、面向过程的语言,C语言广泛应用于底层开发,C语言在计算机体系中占据着不可替代的作用,可以说C语言是编程的基础,也就是说,不管你学习任何语言,都应该把C语言放在首先要学的位置上。下面这张图形象地说明C语言的重要性什么是C语言  C语言是一种通用的、面向过程式的计算机程序设计语言。1972年,为了移植与开发UNIX操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了C语言。 C语言是一种广泛使用的计算机语言,它与Java编程语言一样普及,二者在现代软件程序员之间都得到广泛使用。 当前最新的C语言标准为C18,在它之前的C语言标准有C17、C11...C99等。为什么选择C语言  在过去的长时间里,C语言已经成为了最重要、最流行的编程语言之一。它的成长归功于使用过它的人都对其 非常满意。在过去的20年间,虽然很多人都从C语言转而使用其他语言(例如:C++,Java等),但是C语言凭借其自身实力在众多语言中脱颖而出。 C语言相较于其他高级语言尤其自己独特的优势,C语言在运行时候其效

  • TestNG系列(二)TestNG注解

    前言 TetsNG提供了很多注解,允许测试人员灵活地组织测试用例 一、@Test @Tets是TestNG的核心注解,被注解的方法,表示为一个测试方法。 description属性 @Test(description="yuhao") publicvoidcase1(){ System.out.println("case1方法"); }复制 在测试报告中体现出来   enabled属性 设置为false时,被注解的方法将不会执行 groups属性 对测试方法进行分组,可在类级别或方法级别添加组,类级别分组,表示类里面的所有方法都属于该分组。分组在XML中的调用与普通方法不同,在说XML时会详细介绍。 @Test(groups="yuhao") publicvoidcase1(){ System.out.println("case1方法"); }复制 dependsOnMethods属性 测试方法case1依赖于case2,case2先于case1执行。如果case2失败了则case1也不执行,这叫硬依赖(如果方法发生异常但是被捕获到,此方法不算执行失败,如果异常被抛

  • Reactor事件驱动的两种设计实现:面向对象 VS 函数式编程

    Reactor事件驱动的两种设计实现:面向对象VS函数式编程 这里的函数式编程的设计以muduo为例进行对比说明; Reactor实现架构对比 面向对象的设计类图如下:   函数式编程以muduo为例,设计类图如下:   面向对象的Reactor方案设计 我们先看看面向对象的设计方案,想想为什么这么做;拿出Reactor事件驱动的模式设计图,对比来看,清晰明了;    从左边开始,事件驱动,需要一个事件循环和IO分发器,EventLoop和Poller很好理解;为了让事件驱动支持多平台,Poller上加一个继承结构,实现select、epoller等IO分发器选用; Channel是要监听的事件封装类,核心成员:fd文件句柄;成员方法围绕着fd展开展开,如关注fd的读写事件、取消关注fd的读写事件;核心方法:enableReading/Writing;disableReading/Writing;以及事件到来后的处理方法:handleEvent;在OO设计这里,handleEvent设计成一个虚函数,回调上层实际的数据处理; AcceptChan

  • [译]Serilog Tutorial

    在过去的几年中,结构化日志已经大受欢迎。而Serilog是.NET中最著名的结构化日志类库,我们提供了这份的精简指南来帮助你快速了解并运用它。 0.内容 设定目标 认识Serilog 事件和级别 触发和收集结构化数据 为过滤和关联添加事件标记 大海捞针[Findingneedlesinthehaystack] 下一步是什么? 获得帮助 1.设定目标 你可能之前已经在项目中使用了Serilog,或者你有一个新的项目希望使用Serilog,又或者你只是对结构化日志记录感兴趣:那就非常好!你来对地方了。 然而,更进一步来说,你的目标可能是: 希望在用户之前发现代码中的BUG和错误 为了更快的找到生产环境中的问题 深入的了解系统运行表现 Serilog使用json格式来记录应用程序中的事件,方便我们可以快速的查询日志,关键是可以方便地过滤和查询日志,而不用编写正则表达式。 在本教程中,我们将介绍最关键的几个部分,帮助我们可以在生成环境中提供令人惊叹的诊断能力。[注:原文这句挺拗口] 2.认识Serilog 那就让我们开始吧!为了更好的理解,你可以先创建一个新的.Netconsole项

  • idea新建nodejs_demo1

  • Java在指定字符前面添加字符

    /** *@paramstr:原字符串 *@paramkeyword:字符 *@parambefore:在字符前需要插入的字段 */ publicstaticStringreplacementInfo(Stringstr,Stringkeyword,Stringbefore){ StringBuildersb=newStringBuilder(str); Stringrs=str; try{ //字符第一次出现的位置 intindex=sb.indexOf(keyword); while(index!=-1){ sb.insert(index,before); //下一次出现的位置, index=sb.indexOf(keyword,index+before.length()+1); } rs=sb.toString(); }catch(Exceptione){ System.out.println("更换字符错误!!!"); e.printStackTrace(); } returnrs; }复制  

  • 协同式标注

    nothing 自由软件开发者。承接图像处理,视频智能算法,GIS,三维仿真等方面的工程项目。联系方式QQorwechat:714601476。

  • Plozia 及其博客相关

    欢迎各位来到我的博客! 这里是Plozia,目前是一名高二OIer,会在洛谷,Codeforces,Atcoder上各种写题。 大概快要AFO了。 我的CodeBase:CodeBaseofPlozia,里面有我写题的代码,可能有很小一部分代码会不正确(但至少保证博客里贴出来过的代码除特殊说明外都是正确的)。 *CodeBase已经停止维护。 我的洛谷账号:Plozia 我的博客会写一些学习笔记,题目题解,偶尔会写游记之类的。 然后本人比较菜,是个有tg1=实力但是ARCA会WA8次的nt,简称不会debug( 如果博客有问题可以随时在博客园/qq/洛谷里私信我,我会尽可能的回答。

  • 图片

    读取示例图片,读取示例图片 fromsklearn.datasetsimportload_sample_imagefromsklearn.clusterimportKMeansimportmatplotlib.pyplotasplt china=load_sample_image('china.jpg')plt.imshow(china)plt.show() 观察图片数据格式 image=china[::3,::3]X=image.reshape(-1,3)print(china.shape,image.shape,X.shape) (427,640,3)(143,214,3)(30602,3) 考虑如何压缩 image=china[::3,::3]plt.imshow(image)plt.show() image   可以用matplotlib.image.imread读取图片 importmatplotlib.imageasimgzj=img.imread('F:\\timg.jpg')plt.imshow(zj)plt.show()zj  先缩小图片分

  • 再要你命3K的任务总结

    目前已经到了背到了再要你命3K 的2720那儿。 今天可以搞完3K,后然后就开始1K1K的复习。争取再快速刷一遍,开始做新GREVB的真题。   背完3K要你民,对于我而言真的很不容易!

  • 【MS SQL】数据库维护计划之数据库备份(二)

    上篇【MSSQL】数据库维护计划之数据库备份(一)说了数据库备份的一些概念后,这篇以HRP_KQYY数据库备份为例,进行备份计划设置。   考虑备份的时间、性能和硬盘空间等因素,备份方案做下面设置: 1、每周日凌晨1:00执行数据库完成备份; 2、每周一至周六凌晨1:00执行数据库差异备份; 3、每天在00:00:00和23:59:59之间、每4小时执行数据库的日志备份。   建立3个文件夹: HRP_KQYY_diff:存放差异备份文件; HRP_KQYY_Full:存放完成备份文件; HRP_KQYY_Log:存放事务日志备份文件。   ========================================================================  步骤1:管理->维护计划->新建维护计划->输入维护计划名称。    步骤2:建立3个子计划,并设置3个子计划的执行计划。   步骤2-1: 差异备份的计划设置。 步骤2-2:完整备份的计划设置 步

相关推荐

推荐阅读