• [技术干货] SPL比SQL更难了还是更容易了?-转载
     SPL作为专门用于结构化和半结构化数据的处理技术,在实际应用时经常能比SQL快几倍到几百倍,同时代码还会短很多,尤其在处理复杂计算时优势非常明显。用户在看到这些应用效果后对SPL往往很感兴趣,但又担心掌握起来太难,毕竟SPL的理念和语法都跟SQL有较多不同,这要求用户需要重新了解一些概念和学习新的语法,用户可能会心生疑虑。  那么SPL的上手难度究竟如何呢?这里我们以SQL为起点讨论一下这个问题。  1 SQL一直以来都是使用最广泛的结构化数据查询语言,在实现一般的查询计算时非常简单。像分组汇总一句简单的group by就实现了,相对Java这种要写几十行的高级语言简直不能更简单。而且,SQL的语法设计也符合英语习惯,查询数据时就像说一句英语,这样也大大降低了使用难度。  不过,SQL的简单还主要面向简单查询,情况稍一复杂就不太一样了,三五行的简单查询只存在于教科书中,实际业务要复杂得多。  我们用一个经常举的例子来说明:计算某只股票的最长连续上涨天数。  这个计算并不难,按照自然的方法可以先按交易日排好序,设置一列计数器,逐条记录比较,如果上涨计数器就累加1,否则就清零,最后求出计数器的最大值即可。  但是,很不幸,SQL无法直接描述这个有过程的逻辑(除非用存储过程),于是只能更换思路实现:  select max (consecutive_day) from (select count(*) (consecutive_day       from (select sum(rise_mark) over(order by trade_date) days_no_gain             from (select trade_date,                          case when closing_price>lag(closing_price) over(order by trade_date)                               then 0 else 1 END rise_mark                   from stock_price ) )       group by days_no_gain) 使用另一个思路,把交易记录分组,连续在上涨的记录都分到一组,这样只要计算出最大的那一组的成员数就可以了。分组和统计都是SQL支持的运算,但是SQL只有等值分组,没有按照数据的次序来做的有序分组,结果只能用子查询和窗口函数硬造分组标记,将连续上涨的记录的分组标记设置成相同值,这样才能再进行等值分组求出期望的最大值,这种很绕的写法要理解一下才能看懂。而且这还是利用了SQL在2003标准中提供的窗口函数,可以直接计算比昨天的涨幅,从而比较方便地计算出这个标记,但仍然需要几层嵌套。如果是更早期的SQL92标准,连涨计算都很难,整个句子还会复杂很多倍。  读懂这句SQL就能感受SQL在实现这类计算时并不轻松,不支持过程以及有序计算(窗口函数支持程度仍然较低)的SQL使得原本很简单的求解变得十分困难。  除了缺乏有序计算能力外,SQL还有不支持游离记录,集合化不彻底、缺少对象引用机制等不足,这些都会导致代码编写的困难。一个问题从想到解法(自然思路)到实现(写出代码)变得非常绕,要费很大劲才能实现,这就大幅增加了开发难度。事实上,我们在实际业务中经常看到成百上千行的巨长SQL,经常是因为这种“绕”造成的。这些代码的开发周期经常以周甚至月为单位计,开发成本极高。而且即使写出来,还会出现过一两个月连作者都看不懂的尴尬情况,维护和交接成本也很高。  代码写的复杂,除了开发效率低成本高以外,往往性能也不佳,即使写得出来也跑不快。  还是用一个经常举的简单例子:1 亿条数据中取前 10 名。用SQL写出来并不复杂:  SELECT TOP 10 x FROM T ORDER BY x DESC 1 这个查询用了ORDER BY,严格按此逻辑执行,意味要将全量数据做排序,而大数据排序是一个很慢的动作。如果内存不够还要向外存写缓存,多次磁盘读写更会使性能急剧下降。  我们知道,这个计算根本不需要大排序,只要始终保持一个10个最大数的集合,遍历(一次)数据时去小留大最后剩下的就是最大的10个了,只需要很少内存就可以完成,不涉及反复外存读写。不幸的是,SQL却写不出来这样的算法。  不过还好,虽然语法有限制但可以在工程实现上想办法,很多数据库引擎碰到这个查询会自动进行优化,从而避免过于低效的算法。但是这种自动优化仍然只对简单的情况有效。  现在我们把TopN计算变得复杂一些,计算每个分组内的前10名。SQL实现(已经有点麻烦了):  SELECT * FROM (  SELECT *, ROW_NUMBER() OVER (PARTITION BY Area ORDER BY Amount DESC) rn  FROM Orders ) WHERE rn<=10 这里要先借助窗口函数造一个组内序号出来(组内排序),再用子查询过滤出符合条件的记录。由于集合化不够彻底,需要用分区、排序、子查询才能变相实现,导致这个SQL变得有些绕。而且这时候,大部分数据库的优化器就会犯晕了,猜不出这句 SQL 的目的,只能老老实实地执行按语句书写的逻辑去执行排序(这个语句中还是有ORDER BY的字样),结果性能陡降。  完全靠数据库自动优化靠不住,就得去了解执行计划来改造语句,有时候缺少必要的运算根本无法改造成功,只能写UDF自己算,很难也很繁。甚至UDF也不管用,因为无法改变存储,为了保证性能常常还得自己用Java/C++在外围写,这时的复杂度就非常高了,开发成本也会急剧上升。  本来很多按照正常思维编写就能完成的任务,使用SQL却要经常迂回才能实现,导致代码过长且性能很差,经常自己都很难读懂就更别提数据库的自动优化引擎了。跑的慢就需要使用更多硬件资源来弥补,这又会增加硬件成本,导致开发成本和硬件成本双高!  其实,现在业界已经意识到SQL在处理复杂问题时的局限了,成熟好用的数据仓库并不能只提供SQL。有一些数据仓库已经开始引入了Python、Scala,以及应用MapReduce等技术来解决这个问题,但目前为止效果并不理想。MapReduce性能太差,硬件资源消耗极高,而且代码编写非常繁琐,且仍然有很多难以实现的计算;Python 的Pandas在逻辑功能上还比较强,但细节上比较零乱,明显没有精心设计,有不少重复内容且风格不一致的地方,复杂逻辑描述仍然不容易;而且缺乏大数据计算能力以及相应的存储机制,也很难获得高性能;Scala的DataFrame对象使用沉重,对有序运算支持的也不够好,计算时产生的大量记录复制动作导致性能较差,一定程度甚至可以说是倒退。  这也很容易理解,地基不稳的高楼再在楼上怎么修补也无济于事,只有推到重盖才能从根本解决问题。  而这些正是SPL要解决的问题。  2 SPL没有再基于SQL的关系代数体系,而是发明了新的离散数据集理论以及在此基础上实现的SPL语言(相当于把SQL的高楼推倒重盖)。SPL支持过程计算,并提供了有序计算等多种计算机制,在算法实现上与SQL有很大不同。  拿上面的例子来看。SPL计算股票最长连续上涨天数:  A 1    =stock_price.sort(trade_date) 2    =0 3    =A1.max(A2=if(closing_price> closing_price[-1],A2+1,0)) 基本是按照自然思维解题步骤完成的,排序、比较(用[-1]取上日数据)、求最大值,一二三步完成,十分简洁。  即使使用SQL的实现逻辑,SPL也写起来也很简单:  stock_price.sort(trade_date).group@i(closing_price<closing_price[-1]).max(~.len()) 1 计算思路和前面的 SQL完全相同,但SPL直接支持有序分组,表达起来容易多了,不用再绕来绕去。  语法简洁会大幅提升开发效率,开发成本随之降低。同时,也会带来计算性能上的好处。  A     1    =file(“data.ctx”).create().cursor()     2    =A1.groups(;top(10,amount))    金额在前10名的订单 3    =A1.groups(area;top(10,amount))    每个地区金额在前10名的订单 像前面的TopN 运算在SPL中被认为是和 SUM 和 COUNT 一样的聚合运算,只不过返回值是个集合而已。这样可以将高复杂度的排序转换成低复杂度的聚合运算,而且很还能扩展应用范围。  这里的语句中没有排序字样,不会产生大排序的动作,数据量大也不会涉及硬盘交互,在全集还是分组中计算TopN的语法基本一致,都会有较高的性能。类似的高性能算法SPL还有很多,有序分组、位置索引、并行计算、有序归并等等,都可以大幅提升计算性能。  关于SPL的简洁和高效的原因,我们可以再看这个类比:  计算 1+2+3+…+100,普通人就是一步步地硬加,高斯很聪明地用50 *101一下搞定了。有了乘法这种新的运算类型,无论是描述解法(代码简洁)还是实施计算(高效执行)都有了巨大的改观,完成任务变得简单得多了。  所以我们说,50年前诞生的SQL(关系代数)就像只有加法的算数体系,代码繁琐且性能低下也是必然的。而SPL(离散数据集)则是发明了乘法的算数体系,代码简洁且高效也就是自然而然的事情了。  有人可能会问,使用乘法后确实更简单,但需要聪明的高斯才能想得到,而毕竟不是人人都有高斯这么聪明,那是不是说SPL必须要聪明的程序员才能用起来,会不会难度更大?  这要从两方面来说。  一方面,有些计算原来可能想得出但写不出,像前面提到过的有序分组、不必大排序的TopN用SQL就完不成,最后只能忍受“加法”的绕;而SPL提供了很多“乘法”,你想得出解法的同时也能写出来,甚至还很容易。  另一方面,有些解法由于我们没有高斯聪明确实想不到,但高斯已经想到了,我们只要学会就可以了。1+2+…+100会,2+4+…+500也能会,常用的招术并不多, 做一些练习就都能掌握。但确实也不是天生就能会的,需要一些训练,训练多了,这些手段就变成“自然”思维了,难度也并不大。  3 其实在实际业务中,SQL很难应付的场景还有很多。这里我们试举几个玩爆SQL的例子。  复杂有序计算:用户行为转换漏斗分析 用户登录电商网站/APP后会发生页面浏览、搜索、加购物车、下单、付款等多个操作事件。这些事件按照时间有序,每个事件之后都会有用户流失。漏斗转化分析通常先要统计各个操作事件的用户数量,在此基础上再做转换率等复杂的计算。这里多个事件要在指定时间窗口内完成、按指定次序发生才有效,属于典型的复杂多步有序计算,SQL实现起来就十分不易。  多步骤大数据量跑批 离线跑批涉及的数据量巨大(有时要涉及全量业务数据),且计算逻辑十分复杂,会伴随多步骤计算,彼此有先后顺序。同时跑批通常需要在指定时间窗口内完成,否则会影响业务产生事故。  SQL很难直接实施这些计算,通常要借助存储过程完成。涉及复杂计算时,要用游标读数进行计算,效率很低且无法实施并行计算,效率低下资源占用高。此外,存储过程实现代码往往多达几十步成千上万行,期间会伴随中间结果反复落地,IO成本极高,任务在跑批时间窗口内完不成的现象时有发生。  大数据上多指标计算,反复用关联多 指标计算是金融电信等行业的常用业务,随着数据量和指标数量(组合)增多完,由于计算过程会多次使用明细数据,反复遍历大表,期间还涉及大表关联、条件过滤、分组汇总、去重计数混合运算,同时还伴随高并发。使用SQL已经无法进行实时计算,经常只能采用事先预加工的方式,无法满足多变的实时查询需要。  因为篇幅原因,这里不可能写太长的代码,就用电商漏斗的例子再感受一下。用SQL实现是这样的:  with e1 as (  select uid,1 as step1,min(etime) as t1  from event  where etime>= to\_date('2021-01-10') and etime<to\_date('2021-01-25')  and eventtype='eventtype1' and …  group by 1), e2 as (  select uid,1 as step2,min(e1.t1) as t1,min(e2.etime) as t2  from event as e2  inner join e1 on e2.uid = e1.uid  where e2.etime>= to\_date('2021-01-10') and e2.etime<to\_date('2021-01-25')  and e2.etime > t1 and e2.etime < t1 + 7  and eventtype='eventtype2' and …  group by 1), e3 as (  select uid,1 as step3,min(e2.t1) as t1,min(e3.etime) as t3  from event as e3  inner join e2 on e3.uid = e2.uid  where e3.etime>= to\_date('2021-01-10') and e3.etime<to\_date('2021-01-25')  and e3.etime > t2 and e3.etime < t1 + 7  and eventtype='eventtype3' and …  group by 1) select  sum(step1) as step1,  sum(step2) as step2,  sum(step3) as step3 from  e1  left join e2 on e1.uid = e2.uid  left join e3 on e2.uid = e3.uid  SQL由于缺乏有序计算且集合化不够彻底,需要迂回成多个子查询反复JOIN的写法,编写理解都很困难而且运算性能非常低下。这段代码和漏斗的步骤数量相关,每增加一步数就要再增加一段子查询,实现很繁琐,即使这样,这个计算也并不是所有数据库都能算出来。  同样的计算用SPL来做:  A 1    =["etype1","etype2","etype3"] 2    =file("event.ctx").open() 3    =A2.cursor(id,etime,etype;etime>=date("2021-01-10") && etime<date("2021-01-25") && A1.contain(etype) && …) 4    =A3.group(uid).(~.sort(etime)) 5    =A4.new(~.select@1(etype==A1(1)):first,~:all).select(first) 6    =A5.(A1.(t=if(#==1,t1=first.etime,if(t,all.select@1(etype==A1.~ && etime>t && etime<t1+7).etime, null)))) 7    =A6.groups(;count(~(1)):STEP1,count(~(2)):STEP2,count(~(3)):STEP3) 这个计算按照自然想法,其实只要按uid分组后,循环每个分组按照事件类型列表分别查看是否有对应记录(时间),只是第一个事件比较特殊(需要单独处理),查找到后将其作为第二个事件的输入参数即可,此后第2到第N个事件的处理方式相同(可以用通用代码表达),最后按照用户分组计数即可。  上述SPL的解法与自然思维基本一致,利用有序、集合化分组等特性简单7步就可以完成,很简洁。同时,这段代码能够处理任意步骤数的漏斗。由于只遍历一次数据就可以完成计算,不涉及外存交互,性能也更高。  4 不过,SPL作为一门程序语言,想要使用SPL达到理想效果,还是要求使用者对SPL提供的函数和算法有一定了解,才能从诸多函数中选择适合的,这也是SPL初学者感到困惑的地方。SPL提供的是一套工具箱,使用者根据实际问题开箱选择工具,是先拧螺丝,还是先裁木板完全由需要决定,但一旦掌握了工具箱内各个工具的使用方法,以后无论遇到什么工程问题都能很好解决,即使要对某些现有的东西进行改造(性能优化)也会游刃有余。而SQL提供的工具很少,这就会导致有时即使想到好方法也无从下手,经常需要通过很绕的方式才能实现,不仅难,还很慢。  当然,使用SPL要掌握内容更多,某种意义上讲是“难”了一点。这就好像做应用题,小学生只用四则运算,看起来很简单;而中学生要学会方程的概念,知识要求变高了。但是小学生要根据具体问题来凑出解法,经常挺难的,每次还不一样;中学生则只要用固定套路列方程就完了,你说哪个更容易呢?  掌握方程自然是要有学习的过程,没有掌握这些知识时,会有些无从下手的感觉,因为陌生,所以会觉得难,SPL也一样。如果拿Java比较的话,SPL的学习难度要远低于Java,毕竟Java中那些面向对象、反射等概念也非常复杂。一个程序员连Java都学得会,SPL完全不在话下,只是要习惯一下,不要先入为主。  此外,对于某些十分复杂对性能有极致要求的场景会涉及一些比较高深的算法知识,难度会大一些,这时可以找SPL专家来咨询共同制定解决方案。其实,要解决这些难题重要的是算法而不是语言本身,不管用什么技术这些工作都要做。只不过SQL由于集合化、离散性、有序性等方面的不足要完成这个工作会异常困难,甚至有些时候无能为力,而SPL要表达这类计算就相对简单。  说了这么多,我们可以得出这样的结论。SQL只对简单场景容易,当面对复杂业务逻辑时会因为“绕”导致既难写,跑得又慢,而这些复杂业务才是我们实际应用中的大头(28原则)。要让这些复杂的场景实现变得简单就可以使用SPL来完成,SPL提供了更加简单高效的实现手段。还是那句话,复杂数据计算重点是算法,但算法不仅想出来还要能实现,而且实现起来不能太难(SQL就不行),SPL提供了这种可能。 ———————————————— 版权声明:本文为CSDN博主「石臻臻的杂货铺」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u010634066/article/details/127726441 
  • [技术干货] SQL抽象语法树及改写场景应用
    1 背景 我们平时会写各种各样或简单或复杂的sql语句,提交后就会得到我们想要的结果集。比如sql语句,”select * from t_user where user_id > 10;”,意在从表t_user中筛选出user_id大于10的所有记录。你有没有想过从一条sql到一个结果集,这中间经历了多少坎坷呢?2 SQL引擎 从MySQL、Oracle、TiDB、CK,到Hive、HBase、Spark,从关系型数据库到大数据计算引擎,他们大都可以借助SQL引擎,实现“接受一条sql语句然后返回查询结果”的功能。他们核心的执行逻辑都是一样的,大致可以通过下面的流程来概括:中间蓝色部分则代表了SQL引擎的基本工作流程,其中的词法分析和语法分析,则可以引申出“抽象语法树”的概念。3 抽象语法树 3.1 概念 高级语言的解析过程都依赖于解析树(Parse Tree),抽象语法树(AST,Abstract Syntax Tree)是忽略了一些解析树包含的一些语法信息,剥离掉一些不重要的细节,它是源代码语法结构的一种抽象表示。以树状的形式表现编程语言的结构,树的每个节点ASTNode都表示源码中的一个结构;AST在不同语言中都有各自的实现。解析的实现过程这里不去深入剖析,重点在于当SQL提交给SQL引擎后,首先会经过词法分析进行“分词”操作,然后利用语法解析器进行语法分析并形成AST。下图对应的SQL则是“select username,ismale from userInfo where age>20 and level>5 and 1=1”; 这棵抽象语法树其实就简单的可以理解为逻辑执行计划了,它会经过查询优化器利用一些规则进行逻辑计划的优化,得到一棵优化后的逻辑计划树,我们所熟知的“谓词下推”、“剪枝”等操作其实就是在这个过程中实现的。得到逻辑计划后,会进一步转换成能够真正进行执行的物理计划,例如怎么扫描数据,怎么聚合各个节点的数据等。最后就是按照物理计划来一步一步的执行了。3.2 ANTLR4 解析(词法和语法)这一步,很多SQL引擎采用的是ANTLR4工具实现的。ANTLR4采用的是构建G4文件,里面通过正则表达式、特定语法结构,来描述目标语法,进而在使用时,依赖语法字典一样的结构,将SQL进行拆解、封装,进而提取需要的内容。下图是一个描述SQL结构的G4文件。3.3 示例 3.2.1 SQL解析 在java中的实现一次SQL解析,获取AST并从中提取出表名。首先引入依赖: org.antlr antlr4-runtime 4.7在IDEA中安装ANTLR4插件;示例1,解析SQL表名。使用插件将描述MySQL语法的G4文件,转换为java类(G4文件忽略)。类的结构如下:其中SqlBase是G4文件名转换而来,SqlBaseLexer的作用是词法解析,SqlBaseParser是语法解析,由它生成AST对象。HelloVisitor和HelloListener:进行抽象语法树的遍历,一般都会提供这两种模式,Visitor访问者模式和Listener监听器模式。如果想自己定义遍历的逻辑,可以继承这两个接口,实现对应的方法。读取表名过程,是重写SqlBaseBaseVisitor的几个关键方法,其中TableIdentifierContext是表定义的内容;SqlBaseParser下还有SQL其他“词语”的定义,对应的就是G4文件中的各类描述。比如TableIdentifierContext对应的是G4中TableIdentifier的描述。3.2.2 字符串解析 上面的SQL解析过程比较复杂,以一个简单字符串的解析为例,了解一下ANTLR4的逻辑。1)定义一个字符串的语法:Hello.g42)使用IDEA插件,将G4文件解析为java类3)语法解析类HelloParser,内容就是我们定义的h和world两个语法规则,里面详细转义了G4文件的内容。4)HelloBaseVisitor是采用访问者模式,开放出来的接口,需要自行实现,可以获取xxxParser中的规则信息。5)编写测试类,使用解析器,识别字符串“hi abc”:6)调试后发现命中规则h,解析为Hi和abc两部分。7)如果是SQL的解析,则会一层层的获取到SQL中的各类关键key。4 SqlParser 利用ANTLR4进行语法解析,是比较底层的实现,因为Antlr4的结果,只是简单的文法解析,如果要进行更加深入的处理,就需要对Antlr4的结果进行更进一步的处理,以更符合我们的使用习惯。利用ANTLR4去生成并解析AST的过程,相当于我们在写rpc框架前,先去实现一个netty。因此在工业生产中,会直接采用已有工具来实现解析。Java生态中较为流行的SQL Parser有以下几种(此处摘自网络):fdb-sql-parser 是FoundationDB在被Apple收购前开源的SQL Parser,目前已无人维护。jsqlparser 是基于JavaCC的开源SQL Parser,是General SQL Parser的Java实现版本。Apache calcite 是一款开源的动态数据管理框架,它具备SQL解析、SQL校验、查询优化、SQL生成以及数据连接查询等功能,常用于为大数据工具提供SQL能力,例如Hive、Flink等。calcite对标准SQL支持良好,但是对传统的关系型数据方言支持度较差。alibaba druid 是阿里巴巴开源的一款JDBC数据库连接池,但其为监控而生的理念让其天然具有了SQL Parser的能力。其自带的Wall Filer、StatFiler等都是基于SQL Parser解析的AST。并且支持多种数据库方言。Apache Sharding Sphere(原当当Sharding-JDBC,在1.5.x版本后自行实现)、Mycat都是国内目前大量使用的开源数据库中间件,这两者都使用了alibaba druid的SQL Parser模块,并且Mycat还开源了他们在选型时的对比分析Mycat路由新解析器选型分析与结果.4.1 应用场景 当我们拿到AST后,可以做什么?语法审核:根据内置规则,对SQL进行审核、合法性判断。查询优化:根据where条件、聚合条件、多表Join关系,给出索引优化建议。改写SQL:对AST的节点进行增减。生成SQL特征:参考JIRA的慢SQL工单中,生成的指纹(不一定是AST方式,但AST可以实现)。4.2 改写SQL 提到改写SQL,可能第一个思路就是在SQL中添加占位符,再进行替换;再或者利用正则匹配关键字,这种方式局限性比较大,而且从安全角度不可取。基于AST改写SQL,是用SQL字符串生成AST,再对AST的节点进行调整;通过遍历Tree,拿到目标节点,增加或修改节点的子节点,再将AST转换为SQL字符串,完成改写。这是在满足SQL语法的前提下实现的安全改写。以Druid的SQL Parser模块为例,利用其中的SQLUtils类,实现SQL改写。4.2.1 新增改写 1)原始SQL2)实际执行SQL4.2.2 查询改写前面省略了Tree的遍历过程,需要识别诸如join、sub-query等语法1)简单join查询原始SQL实际执行SQL2)join查询+隐式where条件原始SQL实际执行SQL3)union查询+join查询+子查询+显示where条件原始SQL(unionQuality_Union_Join_SubQuery_ExplicitCondition)实际执行SQL5 总结 本文是基于环境隔离的技术预研过程产生的,其中改写SQL的实现,是数据库在数据隔离上的一种尝试。可以让开发人员无感知的情况下,以插件形式,在SQL提交到MySQL前实现动态改写,只需要在数据表上增加字段、标识环境差异,后续CRUD的SQL都会自动增加标识字段(flag=’预发’、flag=’生产’),所操作的数据只能是当前应用所在环境的数据。来源:51CTO
  • [技术干货] SQL高效查询建议,你学会了吗?
    为什么别人的查询只要几秒,而你的查询语句少则十多秒,多则十几分钟甚至几个小时?与你的查询语句是否高效有很大关系。今天我们来看看如何写出比较高效的查询语句。1.尽量不要使用NULL当默认值在有索引的列上如果存在NULL值会使得索引失效,降低查询速度,该如何优化呢?例如:SELECT * FROM [Sales].[Temp_SalesOrder] WHERE UnitPrice IS NULL我们可以将NULL的值设置成0或其他固定数值,这样保证索引能够继续有效。SELECT * FROM [Sales].[Temp_SalesOrder] WHERE UnitPrice =0这是改写后的查询语句,效率会比上面的快很多。2.尽量不要在WHERE条件语句中使用!=或<>在WHERE语句中使用!=或<>也会使得索引失效,进而进行全表扫描,这样就会花费较长时间了。3.应尽量避免在 WHERE子句中使用 OR遇到有OR的情况,我们可以将OR使用UNION ALL来进行改写例如:SELECT * FROM T1 WHERE NUM=10 OR NUM=20可以改写成SELECT * FROM T1 WHERE NUM=10UNION ALLSELECT * FROM T1 WHERE NUM=204.IN和NOT IN也要慎用遇到连续确切值的时候 ,我们可以使用BETWEEN AND来进行优化例如:SELECT * FROM T1 WHERE NUM IN (5,6,7,8)可以改写成:SELECT * FROM T1 WHERE NUM BETWEEN 5 AND 8.5.子查询中的IN可以使用EXISTS来代替子查询中经常会使用到IN,如果换成EXISTS做关联查询会更快例如:SELECT * FROM T1 WHERE ORDER_ID IN (SELECT ORDER_ID FROM ORDER WHERE PRICE>20);可以改写成:SELECT * FROM T1 AS A WHERE EXISTS (SELECT 1 FROM ORDER AS B WHERE A.ORDER_ID=B.ORDER_ID AND B.PRICE>20)虽然代码量可能比上面的多一点,但是在使用效果上会优于上面的查询语句。6.模糊匹配尽量使用前缀匹配在进行模糊查询,使用LIKE时尽量使用前缀匹配,这样会走索引,减少查询时间。例如:SELECT * FROM T1 WHERE NAME LIKE '%李四%'或者SELECT * FROM T1 WHERE NAME LIKE '%李四'均不会走索引,只有当如下情况SELECT * FROM T1 WHERE NAME LIKE '李四%'才会走索引。上述这些都是平常经常会遇到的,就直接告诉大家怎么操作了,具体可以下去做试验尝试一下。来源:SQL数据库开发
  • [维护宝典] GaussDB(DWS) SQL语句性能优化案例
    问题现象多个表进行LEFT JOIN的查询,执行时间超过2小时,因超时被查杀,执行失败。可能原因SQL语句关联的表多,数据量大时执行速度慢。排查过程分析SQL语句,查看LEFT JOIN的表和条件,以下列出两个相同的表:经过对比发现T6和T62表为同一张表,并且关联条件完全相同,因此此处可以去掉一张表,不改变语句的执行结果。解决方法去掉T62表后,查询可以在2个小时内执行完成,问题得到解决。查询计划如下图所示:
  • [维护宝典] 访问记录0次的表
    【问题描述】一个表的访问,只有seq_scan和idx_scan(视图pg_stat_user_tables) ?如果这两种scan都是0, 说明这个表从创建后就没有被访问  ?    有什么办法能够找到数据库内从来没有被访问过的表,需要清理这些没用的表【解决方案】      1.、访问的可以参考这个(对应视图pg_stat_user_tables),但前提是seq_scan中必须有出现顺序扫描才算,idx_scan中必须有索引扫描才算,但是这个访问数量比实际访问数量要少,因为可能还有除了顺序扫描和索引扫描的其它访问,目前能参考的就这两个数据,没其它的了,有这两个数据,就说明有顺序扫描或索引扫描方式访问了       2.、813版本有个global_table_stat 可以看,目前811这个版本,就之前发的这个视图pg_stat_user_tables,是查,增删改的话看pg_stat_all_tables视图,里面有last_data_changed时间字段,只要数据变动就会记录时间,可以两个视图结合起来看,pg_stat_all_tables视图还有个问题,就是CN或集群重启了信息就不见了,所以可以运行一段时间再看里面的信息。目前还是只有这两个视图可以看;还有个办法就是开审计,但这个代价估计有点大,审计量可能会很大,主要是存储空间膨胀会很验证,因为select语句全部都被记录
  • [维护宝典] 数据库(pg_database_size)和数据库下的表(pg_total_relation_size)大小统计不一致
    【问题背景】在对数据库和数据库下所有表做统计时,FIM页面显示的数据库大小和pg_database_size大小都是50T,所有表的大小是35T,相差了15T,需确认差的15T差在哪【排查过程】1、对空间管控没有做限制,客户统计所有表的sql事实上没有统计全,对于information_schema.tables上是有权限判断的,已发送sql重新做统计现场做完analyze后,目前pg_database_size查出来为22T,表查出来13T,索引查出来24T,查看前台为22T查询语句:a、数据库大小语句:select pg_size_pretty(pg_database_size('postgres'));b、数据库下所有表大小语句:SELECTtable_name,pg_size_pretty(table_size) AS table_size,pg_size_pretty(indexes_size) AS indexes_size,pg_size_pretty(total_size) AS total_sizeFROM (SELECTtable_name,pg_table_size(table_name) AS table_size,pg_indexes_size(table_name) AS indexes_size,pg_total_relation_size(table_name) AS total_sizeFROM (SELECT ('"'table_schema'"."'table_name'"') AS table_nameFROM information_schema.tables) AS all_tablesORDER BY total_size DESC) AS pretty_sizes ;2、select pg_size_pretty(sum(pg_relation_size(relid))) from pg_stat_user_indexes where schemaname in (select nspname from pg_namespace);查询脏页率都达到了90%以上,所处版本查出来信息不准,需要重置表的统计信息再进行脏页率查询,步骤:a、select pg_stat_reset_single_table_counters('schemaname.table'::regclass::oid); -->重置表的统计信息b、analyze tablename-->重新收集表的统计信息c、Select * from pgxc_get_stat_dirty_tables(0,0);-->查询表的脏页率3、现场统计sql有误,重新提供sql进行统计数据库大小:select pg_size_pretty(pg_database_size('postgres'));表空间大小:SELECT sum(pg_total_relation_size_ext('"'table_schema'"."'table_name'"'))/1024/1024/1024 AS size FROM information_schema.tables;索引大小:select pg_size_pretty(sum(pg_relation_size(relid))) from pg_stat_user_indexes where schemaname in (select nspname from pg_namespace);分别查库大小,表大小,索引大小分别查完之后,表大小和索引大小之和大于库的size,主要是索引查出来比库大,统计有问题,怀疑数据膨胀,查询后正常4、用pgxc_get_residualfiles这个函数查出来的结果有残留,统计残留大小,结果只有几k,可忽略不计5、通过pg_tables查询表大小,进行统计,还是有差SELECT sum(pg_total_relation_size(schemaname '.' tablename)) from pg_tables ;6、通过ll列出了base下文件清单,统计表大小的清单求relfilenode,数量比较大,对比一些大表和小表,都对的上7、了解到,之前只对个别表做了analyze,后续对整个业务库做analyze,再查询对比下,做完analyze后,数据库使用空间查出来的和所有表大小差还是没有变化,库为30T左右,表总大小15T8、现场确认了相关信息,收集了所查库的表定义结构信息,后续在家里环境复现此问题,测试后,测试反馈主线版本试了下没有问题,不过开了vacuum,得切到现网版本试下,收集了行存和列存占比数量,在现网环境复现列存:select 'column count:'count(1) as point from pg_class where relkind = 'r' and oid > 16384 and reloptions::text like '%column%';行存:select 'row count:'count(1) as point from pg_class where relkind = 'r' and oid > 16384 and reloptions::text not like '%column%' and reloptions::text not like '%internal_mask%';测试完成,未复现,测完结果正常,还需要回归客户环境排查9、版本给了新的排查方法,排查残留,排查流程如下:a、查询数据库oid,找寻对应数据库的base实例文件select oid from pg_database where datname='postgres';b、base实例目录下面relfilenode导出llgrep -v 'bcm'grep -v 'fsm'grep -v '_C' >> base.txtcp base.txt /data1/c、连接dn,将对应表的relfilenode导出copy (select relfilenode from pg_class ) to '/data1/1.txt';copy (select relfilenode from pg_partition ) to '/data1/2.txt';将1.txt 2.txt整合为一份cat 1.txt 2.txt >>relfilenode.txtd、连接数据库create table relfilenode (b varchar);copy relfilenode from '/data/relfilenode.txt';create table base (b varchar);copy base from '/data1/base.txt';--过滤base下面类似88966.1这种文件delete base where b like '%.%';--查看多余文件select * from base where b not in (select * from relfilenode);排查后,未得到结果10、重新提供排查残留方法,排查语句如下图,排查后发现主有76888文件残留,通过残留工具扫描出来也是,已确认相差部分为残留文件,table求和+残留 基本等于 database size提供残留清理工具,待扫描主备残留后,提供处理方案,清掉残留文件【问题根因】大量残留文件导致统计不一致
  • [互动交流] FlinkSQL任务hive同步不生效。hive没有生成,数据也写不进去。日志也不报错
    CREATE TABLE t_source (id STRING,name STRING,age INT,create_time STRING,par STRING) WITH ('connector' = 'kafka','topic' = 'hudiTest','scan.startup.mode' = 'earliest-offset','properties.bootstrap.servers' = '************','properties.group.id' = 'group01','value.format' = 'json','value.json.fail-on-missing-field' = 'true','value.fields-include' = 'ALL');CREATE TABLE t_hdm(id VARCHAR(20),name VARCHAR(30),age INT,create_time VARCHAR(30),par VARCHAR(20)) PARTITIONED BY (par) WITH ('connector' = 'hudi','path' = 'hdfs://hacluster/tmp/hudi_table_0713_finish','hoodie.datasource.write.table.name' = 'hudi_sync_hive_sink','hoodie.datasource.write.recordkey.field' = 'id','table.type' = 'COPY_ON_WRITE','write.precombine.field' = 'age','write.tasks' = '1','compaction.tasks' = '1','write.rate.limit' = '2000','compaction.async.enabled' = 'true','compaction.trigger.strategy' = 'num_commits','compaction.delta_commits' = '5','hive_sync.enable' = 'true','hive_sync.mode' = 'hms','hive_sync.metastore.uris' = '******','hive_sync.jdbc_url' = '*****','hive_sync.table' = 'hudi_sync_hive_sink','hive_sync.database' = 'default','hive_sync.username' = '******','hive_sync.password' = '******','hive_sync.skip_ro_suffix' = 'true');insert intot_hdmselectid,name,age,create_time,parfromt_source;这条任务hive同步不生效。hive没有生成,数据也写不进去。日志也不报错
  • [技术干货] 深入解析ShardingSphere,开启为数据库提供强劲引擎的全新时代!
    7 月 8 日,由中国信息通信研究院(以下简称中国信通院)、中国通信标准化协会指导,中国通信标准化协会大数据技术标准推进委员会主办的“ 2022 可信数据库峰会”在京召开。SphereEx创始人兼CEO 张亮受邀参会,并于现场进行了《数据库增强引擎 ShardingSphere 实践》的主题演讲。会上,张亮重点强调了未来 ShardingSphere将在Database Plus 理念的指导下,针对不同的场景需求,为数据库全域带来最大限度的复用数据库原生存算能力,为广大用户提供基于数据库上层生态相关的全局扩展、叠加计算等方面的性能。在当前普遍追求技术可信的大背景下,围绕理念、性能与场景这三方面,张亮全面介绍了 ShardingSphere 在数据底座层面的可信能力。理念可信:ShardingSphere 的设计哲学 DatabasePlus Database Plus 是一种分布式数据库系统的设计理念,旨在碎片化的异构数据库上层构建生态,在最大限度的复用数据库原生存算能力的前提下,进一步提供面向全局的扩展和叠加计算能力。使应用和数据库间的交互面向 Database Plus 构建的标准,从而屏蔽数据库碎片化对上层业务带来的差异化影响。其中,『连接、增强、可插拔』是定义 Database Plus 核心价值的三个关键词。1.连接:打造数据库上层标准相对于提供一个全新的标准,Database Plus更倾向于提供一个可以适配于各种数据库 SQL方言和访问协议的中间层,用于便捷地连接碎片化的数据库。通过提供开放的接口用于对接各种数据库,因此在使用体验上与数据库并无二致,同时支持任意的开发语言和数据库访问客户端。此外,Database Plus 能够最大限度支持 SQL 方言间的相互转换,打通了连接异构数据库之间相互访问的通道。目前 ShardingSphere 已支持 MySQL、PostgreSQL、openGauss等数据库协议,以及 MySQL、PostgreSQL、openGauss、SQLServer、Oracle和所有支持SQL92标准的SQL方言。连接层抽象的顶层接口可供其他数据库开放对接,包括:数据库协议、SQL解析和数据库访问等。2.增强:数据库计算增强引擎分布式和云原生时代的到来,将数据库原有的计算和存储能力全部打散,并植入分布式和云原生级别的全新能力,会不可避免出现“重复造轮”。但 Database Plus既重视传统数据库的实践经验,又适配于新一代分布式数据库的设计理念。无论是集中式还是分布式的数据库,Database Plus都能复用数据库的存储和原生计算能力,并在其基础之上提供全局化的能力增强,主要体现在:分布式、数据控制、流量控制三个方面。Database Plus 将支持的数据库种类和增强功能相叠加,以排列组合的方式提供给用户使用。ShardingSphere将功能增强划层面划分为内核层和可选功能层。其中内核层包含查询优化器、分布式事务、执行引擎、权限引擎等与数据库内核强相关的功能,以及调度引擎、分布式治理等与分布式强相关的功能;可选功能层的功能模块由开源社区沉淀而形成,除最具代表性的数据分片和读写分离之外,高可用、弹性伸缩、数据加密、影子库等功能模块也都在逐步的完善之中。3.可插拔:构建数据库功能生态连接和增强的可插拔化,既是Database Plus通用层维持小而美的基石,也是扩展生态无限化的有效保障。通过可插拔体系,Database Plus 将能够真正构建面向数据库的功能生态,将异构数据库的全局能力统一纳管。它不仅面向集中式数据库的分布式化,也同时面向分布式数据库的竖井功能一体化。ShardingSphere 的可插拔架构更像是一个平台,并不会关注具体某一个功能或数据库,而是将所有的功能和连接都插件化,能够在 ShardingSphere生态中实现快速融合与脱离。目前,从最初的 MySQL+数据分片为核心的架构模型,到如今的微内核+可插拔架构,ShardingSphere已进行了彻底的改造。从提供连接的数据库种类和增强功能到内核能力,ShardingSphere已全部面向可插拔。ShardingSphere 的架构核心到外围,由微内核、可插拔接口、插件实现的三层模型组成,层次之间单项依赖,微内核对插件功能完全无需感知,插件之间也无需相互依赖。对于一个拥有200+模块的大型项目来说,架构的解耦和隔离,是社区开放协作,并且将错误影响范围降低至最小的有效保障。性能可信:使用ShardingSphere的核心优势 目前数据库市场碎片化程度日益加重,不同数据库在各领域细分场景下得以充分展现自身优势的同时,也为企业带来了较为复杂的选型问题。而ShardingSphere凭借强劲且可信度较高的性能,天然支持多数据库用户生态,能够为用户有效控制选型及迁移成本。一方面,ShardingSphere能够做到让企业级用户在不变更数据库底层配置的基础上,实现数据库上层的增量加强服务。另一方面,如果用户想要变更数据库底层环境及相关配置,使用ShardingSphere也可以实现无感知的“无缝迁移”。1.ShardingSphere 的极致性能根据上图,可以看到非常明显的差异。毫无疑问,ShardingSphere-JDBC 的性能最为突出。当然,ShardingSphere 作为一款为底层数据库提供增量服务的平台,与底层数据库对接后双方的『适配』情况也关系到在真实生产环境中的性能。而自身高度灵活的可扩展性以及强兼容性,使得 ShardingSphere 具备了面向多种底层数据库的强大兼容能力。此前在ShardingSphere与openGauss的合作中,双方使用16台服务器在超过1小时的测试中,得到了超过1000万tpmC的结果,在极大提升数据库性能极限的同时,ShardingSphere更是满足了 openGauss在海量数据场景下关于可用性以及运维成本等多方面的诉求。Apache ShardingSphere凭借本身强大的兼容性,向下支持多种数据存储引擎,使其可以存在于各类数据库之上,形成一套特有的数据库上层服务生态。而这种能力,恰好能够与国产老牌数据库之间产生明显的互补作用。Apache ShardingSphere愿意同国产数据库共同成长,充分利用现有国产数据库的计算与存储能力,通过插件化方式增强自身核心能力,共同构建健壮的国产数字化基础设施。2.ShardingSphere的易用性在使用层面,用户操作ShardingSphere和操作数据库是没有任何区别的。当然ShardingSphere提供了很多额外的能力,包括数据分片、数据加密、流量治理、读写分离等等。但这些能力在原生数据库上并不具备,因此用户无法通过操作标准SQL来实现这些能力。在考虑到这些后,ShardingSphere提供了DistSQL能力,凭借其『动态生效、无需重启』的特性,开发者和运维人员可以通过 DistSQL来操作管理ShardingSphere,不需要增加更多的学习成本,为ShardingSphere生态带来了强大的动态管理能力。通过DistSQL,用户可以实现在线创建逻辑库、动态配置规则、实时调整存储资源、即时切换事物类型、随时开关SQL日志、预览 SQL路由结果等能力,极大提升了产品的易用性。3.ShardingSphere 的可插拔内核架构上图为 ShardingSphere 微内核架构的组合,可以分成大致的三层。中心部分是微内核,设置了ShardingSphere核心流程,由计算下推引擎和联邦查询组成。计算下推引擎主要负责SQL改写。联邦查询帮助ShardingSphere提升了SQL兼容能力,实现了跨库关联查询及跨库子查询的能力。紫色部分是ShardingSphere所定义的可插拔接口,当开发者想提供新的基于ShardingSphere的能力时,无论是对接新的数据库还是开发多租户的功能,都可以通过可插拔接口直接将该功能植入到 ShardingSphere体系中。最外侧绿色部分是开发者基于ShardingSphere所实现的具体内容,包括根据自身业务场景和商业诉求进行适配后所实现的具体能力,这部分并不强迫进行开源。此外这部分的能力也能够以系统级别植入到公司自己的ShardingSphere内核层面,进而实现完全自主可控的数据库平台。场景可信:ShardingSphere适用场景 此外,针对不同的用户需求ShardingSphere能够在多元化的应用场景下实现完美适配。前面提到,ShardingSphere能够复用数据库的存储和原生计算能力,并在其基础之上提供全局化的能力增强,主要体现在分布式、数据控制、流量控制三个方面。1.分布式数据库为解决原有方案的技术瓶颈,降低更换架构带来的复杂性风险,在不更换原有架构前提下,ShardingSphere能够实现数据库同步、管理多个异构数据库集群、线性提升数据存储容量及并发吞吐。进而为用户提供基于数据分片,分布式事务、弹性伸缩的分布式数据库解决方案,使用户的数据库兼具单机交易型数据库稳定性和分布式数据库的扩展能力。2.面向数据控制用户可以通过ShardingSphere对数据本身实现控制,如数据加解密、SQL审计等。此外为防止数据泄露,用户可以使用 ShardingSphere 在基于产品的数据加密和数据脱敏功能之上升级为数据安全解决方案,进而能够在不改动原有代码的前提下,为企业提供跨平台、异构环境的数据安全解决方案。3.面向流量控制基于本身内核的SQL解析能力以及可插拔平台架构,ShardingSphere能够实现压测数据与生产数据的隔离,帮助应用自动路由,同时支持全链路压测,进而帮助用户实现在生产环境下获得较为准确地反应系统真实容量水平和性能的测试结果。作为数据库相关领域的强劲引擎,ShardingSphere 将以其极致性能处理、高易用、可插拔内核架构的核心特点,切实帮助各企业级用户解决其业务场景中的痛点问题,从而充分释放数据潜能,加速自身业务增长。来源:大数据技术标准推进委员会
  • [技术干货] 开源SPL强化MangoDB计算-转载
    MongoDB是NoSQL数据库的典型代表,支持文档结构的存储方式数据存储和使用更为便捷,数据存取效率也很高,但计算能力较弱,实际使用中涉及MongoDB的计算尤其是复杂计算会很麻烦,这就需要具备强计算能力的数据处理引擎与其配合。开源集算器SPL是一款专业结构化数据计算引擎,拥有丰富的计算类库和完备、不依赖数据库的计算能力。SPL提供了独立的过程计算语法,尤其擅长复杂计算,可以增强MongoDB的计算能力,完成分组汇总、关联计算、子查询等通通不在话下。常规查询MongoDB不容易搞定的连接JOIN运算,用SPL很容易搞定:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    /连接MongDB2    =mongo_shell(A1,"c1.find()").fetch()    /获取数据3    =mongo_shell(A1,"c2.find()").fetch()    4    =A2.join(user1:user2,A3:user1:user2,output)    /关联计算5    >A1.close()    /关闭连接 单表多次参与运算,复用计算结果:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,“course.find(,{_id:0})”).fetch()    /获取数据3    =A2.group(Sno).((avg   = ~.avg(Grade), ~.select(Grade>avg))).conj()    /计算成绩大于平均值4    >A1.close()     IN计算:A    B1    =mongo_open("mongodb://localhost:27017/test")    2    =mongo_shell(A1,"orders.find(,{_id:0})")    /获取数据3    =mongo_shell(A1,"employee.find({STATE:'California'},{_id:0})").fetch()    /过滤employee数据4    =A3.(EID).sort()    /取出EID并排序5    =A2.select(A4.pos@b(SELLERID)).fetch()    /二分法查找6    >A1.close()     外键对象化,外键指针不仅方便,效率也高:A    B1    =mongo_open("mongodb://localhost:27017/local")    2    =mongo_shell(A1,"Progress.find({},   {_id:0})").fetch()    /获取Progress数据3    =A2.groups(courseid;   count(userId):popularityCount)    /按课程分组计数4    =mongo_shell(A1,"Course.find(,{title:1})").fetch()    /获取Course数据5    =A3.switch(courseid,A4:_id)    /外键连接6    =A5.new(popularityCount,courseid.title)    /创建结果集7    =A1.close()     APPLY算法的简单实现:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"users.find()").fetch()    /获取users数据3    =mongo_shell(A1,"workouts.find()").fetch()    /获取workouts数据4    =A2.conj(A3.select(A2.workouts.pos(_id)).derive(A2.name))    /查询_id 值workouts 序列的记录5    >A1.close()     集合运算,合并交差:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"emp1.find()").fetch()    3    =mongo_shell(A1,"emp2.find()").fetch()    4    =[A2,A3].conj()    /多序列合集5    =[A2,A3].merge@ou()    /全行对比求并集6    =[A2,A3].merge@ou(_id,   NAME)    /键值对比求并集7    =[A2,A3].merge@oi()    /全行对比求交集8    =[A2,A3].merge@oi(_id,   NAME)    /键值对比求交集9    =[A2,A3].merge@od()    /全行对比求差集10    =[A2,A3].merge@od(_id,   NAME)    /键值对比求差集11    >A1.close()     在序列中查找成员序号:A    B1    =mongo_open("mongodb://localhost:27017/local)    2    =mongo_shell(A1,"users.find({name:'jim'},{name:1,friends:1,_id:0})")   .fetch()    3    =A2.friends.pos("luke")    /从friends序列中获取成员序号4    =A1.close()     多成员集合的交集:A    B1    [Chemical,   Biology, Math]    /课程2    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    3    =mongo_shell(A2,"student.find()").fetch()    /获取student数据4    =A3.select(Lesson^A1!=[])    /查询选修至少一门的记录5    =A4.new(_id,   Name, ~.Lesson^A1:Lession)    /计算出结果6    >A2.close()    复杂计算TOPN运算:A    B    1    =mongo_open("mongodb://127.0.0.1:27017/test")        2    =mongo_shell(A1,"last3.find(,{_id:0};{variable:1})")    /获取last3数据,并按variable排序    3    for A2;variable    =A3.top(3;-timestamp)    /选出timestamp最晚的3个4        =@|B3    /将选出文档追加到B4中5    =B4.minp(~.timestamp)         /选出timstamp最早的文档    6    >mongo_close(A1)         嵌套结构的聚合:A1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")2    =mongo_shell(A1,"computer.find()").fetch()3    =A2.new(_id:ID,income.array().sum():INCOME,output.array().sum():OUTPUT)4    >A1.close() 合并多属性子文档:A    B    C1    =mongo_open("mongodb://localhost:27017/local")        2    =mongo_shell(A1,"c1.find(,{_id:0};{name:1})")        3    =create(_id,   readUsers)        /创建结果序表4    for   A2;name    =A4.conj(acls.read.users|acls.append.users|acls.edit.users|acls.fullControl.users).id()    /取出所有users字段5        >A3.insert(0,   A4.name, B4)    /插入本组数据6    =A1.close()         嵌套List子文档的查询A    B1    =mongo_open("mongodb://localhost:27017/local")    2    =mongo_shell(A1,"Cbettwen.find(,{_id:0})").fetch()    3    =A2.conj((t=~.objList.data.dataList,   t.select((s=float(~.split@c1()(1)), s>6154   && s<=6155))))    /找到符合条件的字符串4    =A1.close()     交叉汇总:A1    =mongo_open("mongodb://localhost:27017/local")2    =mongo_shell(A1,"student.find()").fetch()3    =A2.group(school)4    =A3.new(school:school,~.align@a(5,sub1).(~.len()):sub1,~.align@a(5,sub2).(~.len()):sub2)5    =A4.new(school,sub1(5):sub1-5,sub1(4):sub1-4,sub1(3):sub1-3,sub1(2):sub1-2,sub1(1):sub1-1,sub2(5):sub2-5,sub2(4):sub2-4,sub2(3):sub2-3,sub2(2):sub2-2,sub2(1):sub2-1)6    =A1.close() 分段分组A    B1    [3000,5000,7500,10000,15000]    /Sales分段区间2    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    3    =mongo_shell(A2,"sales.find()").fetch()    4    =A3.groups(A1.pseg(~.SALES):Segment;count(1):   number)    /根据 SALES 区间分组统计员工数5    >A2.close()     分类分组A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"books.find()")    3    =A2.groups(addr,book;count(book):   Count)    /分组计数4    =A3.groups(addr;sum(Count):Total)    /分组统计5    =A3.join(addr,A4:addr,Total)    /关联计算6    >A1.close()     数据写入导出成CSV:A    B1    =mongo_open("mongodb://localhost:27017/raqdb")    2    =mongo_shell(A1,"carInfo.find(,{_id:0})")    3    =A2.conj((t=~,cars.car.new(t.id:id,   t.cars.name, ~:car)))    /对car字段进行拆分成行4    =file("D:\\data.csv").export@tc(A3)    /导出生成csv文件5    >A1.close()     更新数据库(MongoDB到MySQL):A    B1    =mongo_open("mongodb://localhost:27017/raqdb")    /连接MongDB2    =mongo_shell(A1,"course.find(,{_id:0})").fetch()    3    =connect("myDB1")    /连接mysql4    =A3.query@x("select   * from course2").keys(Sno, Cno)    5    >A3.update(A2:A4,   course2, Sno, Cno, Grade; Sno,Cno)    /向mysql更新数据6    >A1.close()     更新数据库(MySQL到MongoDB):A    B1    =connect("mysql")    /连接mysql2    =A1.query@x("select   * from course2")    /获取表course2数据3    =mongo_open("mongodb://localhost:27017/raqdb")    /连接MongDB4    =mongo_insert(A3,   "course",A2)    /将MySQL表course2导入MongoDB集合course5    >A3.close()     混合计算借助SPL还很容易实现MongoDB与其他数据源进行混合计算:A    B1    =mongo_open("mongodb://localhost:27017/test")    /连接MongDB2    =mongo_shell(A1,"emp.find({'$and':[{'Birthday':{'$gte':'"+string(begin)+"'}},{'Birthday':{'$lte':'"+string(end)+"'}}]},{_id:0})").fetch()    /查询某时间段的记录3    =A1.close()    /关闭MongoDB4    =myDB1.query("select   * from cities")    /获取mysql中表cities数据5    =A2.switch(CityID,A4:   CityID)    /外键关联6    =A5.new(EID,Dept,CityID.CityName:CityName,Name,Gender)    /创建结果集7    return   A6    /返回SQL支持SPL除了原生语法,还提供了相当于SQL92标准的SQL支持,可以使用SQL查询MongoDB了,比如前面的关联计算:A1    =mongo_open("mongodb://127.0.0.1:27017/test")2    =mongo_shell(A1,"c1.find()").fetch()3    =mongo_shell@x(A1,"c2.find()").fetch()4    $select s.* from {A2} as s left join {A3}   as r on s.user1=r.user1 and s.user2=r.user2 where r.income>0.3应用集成不仅如此,SPL提供了标准JDBC/ODBC等应用程序接口,集成调用很方便。如JDBC的使用:…Class.forName("com.esproc.jdbc.InternalDriver");Connection conn = DriverManager.getConnection("jdbc:esproc:local://");PrepareStatement st=con.prepareStatement("call splScript(?)"); // splScript为spl脚本文件名st.setObject(1,"California");st.execute();ResultSet rs = st.getResultSet();…有了这些功能,增强MongoDB的计算能力可不是说说而已,要不要下载试试?————————————————版权声明:本文为CSDN博主「石臻臻的杂货铺」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/u010634066/article/details/125854301
  • [其他] EI企业智能2022年7月高热贴合集
    ## EI企业智能2022年7月高热贴合集 以下是EI企业智能板块在2022年7月份的高热贴的合集,虽然今年的三伏天已热的突破历史,但本月AI开发平台ModelArts、数仓GaussDB(DWS)板块的热度更高。 另外板块名称有一些小小的修改,比如 **ModelArts** 改为了 `AI开发平台ModelArts` **HiLens** 改为了 `华为HiLens & ModelBox` 新名称新气象啊~ ## 数仓GaussDB(DWS) GaussDB 8.0.0.1版本 巡检工具806,互信中提到的sshTool.sh文件从哪里获取?https://bbs.huaweicloud.com/forum/thread-193193-1-1.html autovacuum如何配置可以实现定时全库全表analyse?https://bbs.huaweicloud.com/forum/thread-193348-1-1.html 【DWS】【sql】pg_stat_user_functions 为什么没有数据:https://bbs.huaweicloud.com/forum/thread-193726-1-1.html dws中sql在执行Streaming(type: REDISTRIBUTE)之前先进行HashAggregate是否能提升性能:https://bbs.huaweicloud.com/forum/thread-193978-1-1.html 【GaussDB 8.1.1】【Oracle的months_between函数迁移】Oracle函数迁移效率不行:https://bbs.huaweicloud.com/forum/thread-193925-1-1.html gaussdb如果查询所有表名及主键字段名称?或者如何查询单表的主键字段名称:https://bbs.huaweicloud.com/forum/thread-193958-1-1.html 如何通过sql实现全表的分析:https://bbs.huaweicloud.com/forum/thread-194033-1-1.html 修改autovacuum参数时报错:https://bbs.huaweicloud.com/forum/thread-193927-1-1.html MRS的Flink连接DWS,运行12小时报错:https://bbs.huaweicloud.com/forum/thread-194438-1-1.html dws执行计划中的actual time代表什么:https://bbs.huaweicloud.com/forum/thread-194574-1-1.html 为何 DWS to_date(xxx,'yyyymmdd')关联比 cast(xxx as date) 关联效率慢:https://bbs.huaweicloud.com/forum/thread-194316-1-1.html 【数仓GaussDB(DWS)】【bytea类型】使用postgresql.jar驱动包解析出错:https://bbs.huaweicloud.com/forum/thread-195190-1-1.html 【华为云DWS】【ODBC】PHP ODBC连接公有云上的DWS数据库怎么操作啊:https://bbs.huaweicloud.com/forum/thread-195440-1-1.html 【GaussDB】【bytea类型】column "bytes_" is of type bytea but expressio:https://bbs.huaweicloud.com/forum/thread-195501-1-1.html GaussDB(DWS)存储过程exception捕捉others异常后,记录日志的语句不会提交:https://bbs.huaweicloud.com/forum/thread-195599-1-1.html ## AI开发平台ModelArts 【CodeLab】开发环境有点老,有计划更新吗:https://bbs.huaweicloud.com/forum/thread-192975-1-1.html 2022华为开发者大赛 · 崇本英才·智汇吴江· 无人车挑战赛 判分失败 scoring job failed:https://bbs.huaweicloud.com/forum/thread-193791-1-1.html 【沈阳昇腾创新中心+openlab训练回归模型警告问题】(NPU使用问题):https://bbs.huaweicloud.com/forum/thread-193768-1-1.html 用yolov5模型训练,上传数据集应该遵循哪种格式,是否需要添加验证集?https://bbs.huaweicloud.com/forum/thread-193706-1-1.html ModelArts支持视频流分析吗? https://bbs.huaweicloud.com/forum/thread-193943-1-1.html modelarts训练作业时,从obs下载文件,下载速率是多少?https://bbs.huaweicloud.com/forum/thread-193705-1-1.html 【Codelab】请问下Codelab里打开的notebook,是否可能SSH接入:https://bbs.huaweicloud.com/forum/thread-194854-1-1.html 【ModelArts】【Notebook】VScode不能用SSH连接ModelArts Notebook:https://bbs.huaweicloud.com/forum/thread-194556-1-1.html ModelArts训练开发故障“临终遗言“:https://bbs.huaweicloud.com/forum/thread-194442-1-1.html 【在线服务】【404】在线服务部署后预测失败是什么原因呀:https://bbs.huaweicloud.com/forum/thread-194910-1-1.html 【数据集】【分割】请教一下这个数据集的annotation怎么看?https://bbs.huaweicloud.com/forum/thread-194873-1-1.html 【ModelArts产品】【模型训练功能】用coco2014数据集训练yolov3-darknet53模型报错:https://bbs.huaweicloud.com/forum/thread-194920-1-1.html 金融情绪分析FinBERT 无法正常跑通(调小batch):https://bbs.huaweicloud.com/forum/thread-195281-1-1.html 【ModelArts产品】【模型训练功能】tacotron2训练报错,缺少unidecode模组:https://bbs.huaweicloud.com/forum/thread-195327-1-1.html notebook的资费是不是涨了:https://bbs.huaweicloud.com/forum/thread-195442-1-1.html ## 华为HiLens & ModelBox 用hilens studio创建技能时,再导入OM文件时,一直在报导入模型失败:https://bbs.huaweicloud.com/forum/thread-194172-1-1.html hilens 技能开发页面导入自己模型,启动技能没反应:https://bbs.huaweicloud.com/forum/thread-193032-1-1.html HiLens如何用HDMI来连接显示屏:https://bbs.huaweicloud.com/forum/thread-193510-1-1.html hilens设备告警看不懂,日志内容怎么看:https://bbs.huaweicloud.com/forum/thread-194133-1-1.html hilens studio与手机摄像头实现视频流显示的错误:https://bbs.huaweicloud.com/forum/thread-194162-1-1.html hilens怎么保存视频(推理后):https://bbs.huaweicloud.com/forum/thread-194037-1-1.html hilens的摄像头如何录制视频,并且保存在自己想要保存 的位置:https://bbs.huaweicloud.com/forum/thread-194434-1-1.html 打不开hilens kit的ip地址:https://bbs.huaweicloud.com/forum/thread-194688-1-1.html ## 混合云FusionInsight hive元数据库连接:https://bbs.huaweicloud.com/forum/thread-192987-1-1.html Flink的准备安全认证问题:https://bbs.huaweicloud.com/forum/thread-193349-1-1.html flink提交任务运行失败:https://bbs.huaweicloud.com/forum/thread-193657-1-1.html 如何查看sceurity 是否配置成功(Flink客户端):https://bbs.huaweicloud.com/forum/thread-193744-1-1.html Flink的JDBCsink,batchintervalMs和BatchSize参数问题:https://bbs.huaweicloud.com/forum/thread-195124-1-1.html spark客户端提交代码报错Unable to obtain password from user 找不到密码:https://bbs.huaweicloud.com/forum/thread-195544-1-1.html ## MapReduce服务 【MRS产品】【hetuengine功能】hetu配置clickhouse数据源与clickhouse查询的结果不一致:https://bbs.huaweicloud.com/forum/thread-192997-1-1.html 【MRS产品】【hetu配置数据源功能】hetu是否能配置hive的内置元数据库数据源:https://bbs.huaweicloud.com/forum/thread-193786-1-1.html 【MRS】【hetu查询】进入hetu命令行不管输入什么都报错:Error running command: java.net.:https://bbs.huaweicloud.com/forum/thread-195417-1-1.html
  • [知识分享] openGauss内核分析:查询重写
    摘要:查询重写优化既可以基于关系代数的理论进行优化,也可以基于启发式规则进行优化。本文分享自华为云社区《openGauss内核分析(四):查询重写》,作者:酷哥。查询重写SQL语言是丰富多样的,非常的灵活,不同的开发人员依据经验的不同,手写的SQL语句也是各式各样,另外还可以通过工具自动生成。SQL语言是一种描述性语言,数据库的使用者只是描述了想要的结果,而不关心数据的具体获取方式,输入数据库的SQL语言很难做到是以最优形式表示的,往往隐含了一些冗余信息,这些信息可以被挖掘用来生成更加高效的SQL语句。查询重写就是把用户输入的SQL语句转换为更高效的等价SQL,查询重写遵循两个基本原则。• 等价性:原语句和重写后的语句,输出结果相同。• 高效性:重写后的语句,比原语句在执行时间和资源使用上更高效。查询重写优化既可以基于关系代数的理论进行优化,例如谓词下推、子查询优化等,也可以基于启发式规则进行优化,例如Outer Join消除、表连接消除等。查询重写是基于规则的逻辑优化。在代码层面,查询重写的架构如下:下面以外连接消除Outer2Inner—外连接转内连接为例分析查询重写过程:在left outer join或者right outer join中,如果查询条件中存在逻辑上能够包含IS NOT NULL,例如c1 > 0,可以将查询转换成INNER JOIN,从而减少关联处理产生的中间结果集外连接消除Outer2Inner下面首先以一个例子来说明各种多表连接方式的区别create table t1(c1 int, c2 int); create table t2(c1 int, c2 int); insert into t1 values(1, 10); insert into t1 values(2, 20); insert into t1 values(3, 30); insert into t2 values(1, 100); insert into t2 values(3, 300); insert into t2 values(5, 500);内连接inner join:返回两个表都满足的组合,相当于取两个表的交集SELECT * FROM t1 inner JOIN t2 ON t1.c1 = t2.c1;左连接 left outer join:返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值SELECT * FROM t1 Left OUTER JOIN t2 ON t1.c1 = t2.c1;右连接 right outer join:返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值SELECT * FROM t1 right OUTER JOIN t2 ON t1.c1 = t2.c1;全连接 full join:返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值,相当于取两个表并集SELECT * FROM t1 full JOIN t2 ON t1.c1 = t2.c1;在以上实验的基础上增加t2表的where条件left join和inner join的结果是一样的,这是因为查询条件中包含WHERE t2.c2 >100这个条件,t2表所有不匹配元组均被过滤掉(包括空值),因此可以进行查询转换left-outer join -> inner join,能够有效减小t1和t2关联产生的结果集,达到性能提升的目的。在openGauss数据库系统中,subquery_planner会遍历查询树中的rtable,看看是否有RTE_JOIN类型的节点存在,设置hasOuterJoins标志量,从而进入到reduce_outer_joins接口,满足外连接消除条件时再执行外连接的消除。 reduce_outer_Joins函数内部做两个动作,(1)reduce_outer_joins_pass1预检查,就是检查jointree中是否含有外链接,以及一些引用表的信息,为动作2做好信息采集准备,重点参考数据结构reduce_outer_joins_state;(2)reduce_outer_joins_pass2真正完成消除外链接。void reduce_outer_joins(PlannerInfo* root) { reduce_outer_joins_state* state = NULL; state = reduce_outer_joins_pass1((Node*)root->parse->jointree); /* planner.c shouldn't have called me if no outer joins */ if (state == NULL || !state->contains_outer) ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), (errmsg("so where are the outer joins?")))); reduce_outer_joins_pass2((Node*)root->parse->jointree, state, root, NULL, NIL, NIL); }利用上一期的分析方法,可以得到查询树内存结构(查询树Query结构体中targetList存储目标属性语义分析结果,rtable存储FROM子句生成的范围表,jointree的quals字段存储WHERE子句语义分析的表达式树)对比reduce_outer_joins运行前后查询树,jointree和rtable中的jointype都由join_left转换为join_inner,即外连接已转为内连接(gdb) p *((JoinExpr*)(parse->jointree->fromlist->head.data->ptr_value)) $1 = {type = T_JoinExpr, jointype = JOIN_INNER, isNatural = false, larg = 0x7fdfb345cd08, rarg = 0x7fdfb345e2e8, usingClause = 0x0, quals = 0x7fdfb2f0b8a8, alias = 0x0, rtindex = 3} (gdb) p *(RangeTblEntry*)(parse->rtable->tail.data->ptr_value) $2 = {type = T_RangeTblEntry, rtekind = RTE_JOIN, relname = 0x0, partAttrNum = 0x0, relid = 0, partitionOid = 0, isContainPartition = false, subpartitionOid = 0, isContainSubPartition = false, refSynOid = 0, partid_list = 0x0, relkind = 0 '\000', isResultRel = false, tablesample = 0x0, timecapsule = 0x0, ispartrel = false, ignoreResetRelid = false, subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, …}
  • [技术干货] 开源SPL强化MangoDB计算-转载
    MongoDB是NoSQL数据库的典型代表,支持文档结构的存储方式数据存储和使用更为便捷,数据存取效率也很高,但计算能力较弱,实际使用中涉及MongoDB的计算尤其是复杂计算会很麻烦,这就需要具备强计算能力的数据处理引擎与其配合。开源集算器SPL是一款专业结构化数据计算引擎,拥有丰富的计算类库和完备、不依赖数据库的计算能力。SPL提供了独立的过程计算语法,尤其擅长复杂计算,可以增强MongoDB的计算能力,完成分组汇总、关联计算、子查询等通通不在话下。常规查询MongoDB不容易搞定的连接JOIN运算,用SPL很容易搞定:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    /连接MongDB2    =mongo_shell(A1,"c1.find()").fetch()    /获取数据3    =mongo_shell(A1,"c2.find()").fetch()    4    =A2.join(user1:user2,A3:user1:user2,output)    /关联计算5    >A1.close()    /关闭连接 单表多次参与运算,复用计算结果:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,“course.find(,{_id:0})”).fetch()    /获取数据3    =A2.group(Sno).((avg   = ~.avg(Grade), ~.select(Grade>avg))).conj()    /计算成绩大于平均值4    >A1.close()     IN计算:A    B1    =mongo_open("mongodb://localhost:27017/test")    2    =mongo_shell(A1,"orders.find(,{_id:0})")    /获取数据3    =mongo_shell(A1,"employee.find({STATE:'California'},{_id:0})").fetch()    /过滤employee数据4    =A3.(EID).sort()    /取出EID并排序5    =A2.select(A4.pos@b(SELLERID)).fetch()    /二分法查找6    >A1.close()     外键对象化,外键指针不仅方便,效率也高:A    B1    =mongo_open("mongodb://localhost:27017/local")    2    =mongo_shell(A1,"Progress.find({},   {_id:0})").fetch()    /获取Progress数据3    =A2.groups(courseid;   count(userId):popularityCount)    /按课程分组计数4    =mongo_shell(A1,"Course.find(,{title:1})").fetch()    /获取Course数据5    =A3.switch(courseid,A4:_id)    /外键连接6    =A5.new(popularityCount,courseid.title)    /创建结果集7    =A1.close()     APPLY算法的简单实现:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"users.find()").fetch()    /获取users数据3    =mongo_shell(A1,"workouts.find()").fetch()    /获取workouts数据4    =A2.conj(A3.select(A2.workouts.pos(_id)).derive(A2.name))    /查询_id 值workouts 序列的记录5    >A1.close()     集合运算,合并交差:A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"emp1.find()").fetch()    3    =mongo_shell(A1,"emp2.find()").fetch()    4    =[A2,A3].conj()    /多序列合集5    =[A2,A3].merge@ou()    /全行对比求并集6    =[A2,A3].merge@ou(_id,   NAME)    /键值对比求并集7    =[A2,A3].merge@oi()    /全行对比求交集8    =[A2,A3].merge@oi(_id,   NAME)    /键值对比求交集9    =[A2,A3].merge@od()    /全行对比求差集10    =[A2,A3].merge@od(_id,   NAME)    /键值对比求差集11    >A1.close()     在序列中查找成员序号:A    B1    =mongo_open("mongodb://localhost:27017/local)    2    =mongo_shell(A1,"users.find({name:'jim'},{name:1,friends:1,_id:0})")   .fetch()    3    =A2.friends.pos("luke")    /从friends序列中获取成员序号4    =A1.close()     多成员集合的交集:A    B1    [Chemical,   Biology, Math]    /课程2    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    3    =mongo_shell(A2,"student.find()").fetch()    /获取student数据4    =A3.select(Lesson^A1!=[])    /查询选修至少一门的记录5    =A4.new(_id,   Name, ~.Lesson^A1:Lession)    /计算出结果6    >A2.close()    复杂计算TOPN运算:A    B    1    =mongo_open("mongodb://127.0.0.1:27017/test")        2    =mongo_shell(A1,"last3.find(,{_id:0};{variable:1})")    /获取last3数据,并按variable排序    3    for A2;variable    =A3.top(3;-timestamp)    /选出timestamp最晚的3个4        =@|B3    /将选出文档追加到B4中5    =B4.minp(~.timestamp)         /选出timstamp最早的文档    6    >mongo_close(A1)         嵌套结构的聚合:A1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")2    =mongo_shell(A1,"computer.find()").fetch()3    =A2.new(_id:ID,income.array().sum():INCOME,output.array().sum():OUTPUT)4    >A1.close() 合并多属性子文档:A    B    C1    =mongo_open("mongodb://localhost:27017/local")        2    =mongo_shell(A1,"c1.find(,{_id:0};{name:1})")        3    =create(_id,   readUsers)        /创建结果序表4    for   A2;name    =A4.conj(acls.read.users|acls.append.users|acls.edit.users|acls.fullControl.users).id()    /取出所有users字段5        >A3.insert(0,   A4.name, B4)    /插入本组数据6    =A1.close()         嵌套List子文档的查询A    B1    =mongo_open("mongodb://localhost:27017/local")    2    =mongo_shell(A1,"Cbettwen.find(,{_id:0})").fetch()    3    =A2.conj((t=~.objList.data.dataList,   t.select((s=float(~.split@c1()(1)), s>6154   && s<=6155))))    /找到符合条件的字符串4    =A1.close()     交叉汇总:A1    =mongo_open("mongodb://localhost:27017/local")2    =mongo_shell(A1,"student.find()").fetch()3    =A2.group(school)4    =A3.new(school:school,~.align@a(5,sub1).(~.len()):sub1,~.align@a(5,sub2).(~.len()):sub2)5    =A4.new(school,sub1(5):sub1-5,sub1(4):sub1-4,sub1(3):sub1-3,sub1(2):sub1-2,sub1(1):sub1-1,sub2(5):sub2-5,sub2(4):sub2-4,sub2(3):sub2-3,sub2(2):sub2-2,sub2(1):sub2-1)6    =A1.close() 分段分组A    B1    [3000,5000,7500,10000,15000]    /Sales分段区间2    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    3    =mongo_shell(A2,"sales.find()").fetch()    4    =A3.groups(A1.pseg(~.SALES):Segment;count(1):   number)    /根据 SALES 区间分组统计员工数5    >A2.close()     分类分组A    B1    =mongo_open("mongodb://127.0.0.1:27017/raqdb")    2    =mongo_shell(A1,"books.find()")    3    =A2.groups(addr,book;count(book):   Count)    /分组计数4    =A3.groups(addr;sum(Count):Total)    /分组统计5    =A3.join(addr,A4:addr,Total)    /关联计算6    >A1.close()     数据写入导出成CSV:A    B1    =mongo_open("mongodb://localhost:27017/raqdb")    2    =mongo_shell(A1,"carInfo.find(,{_id:0})")    3    =A2.conj((t=~,cars.car.new(t.id:id,   t.cars.name, ~:car)))    /对car字段进行拆分成行4    =file("D:\\data.csv").export@tc(A3)    /导出生成csv文件5    >A1.close()     更新数据库(MongoDB到MySQL):A    B1    =mongo_open("mongodb://localhost:27017/raqdb")    /连接MongDB2    =mongo_shell(A1,"course.find(,{_id:0})").fetch()    3    =connect("myDB1")    /连接mysql4    =A3.query@x("select   * from course2").keys(Sno, Cno)    5    >A3.update(A2:A4,   course2, Sno, Cno, Grade; Sno,Cno)    /向mysql更新数据6    >A1.close()     更新数据库(MySQL到MongoDB):A    B1    =connect("mysql")    /连接mysql2    =A1.query@x("select   * from course2")    /获取表course2数据3    =mongo_open("mongodb://localhost:27017/raqdb")    /连接MongDB4    =mongo_insert(A3,   "course",A2)    /将MySQL表course2导入MongoDB集合course5    >A3.close()     混合计算借助SPL还很容易实现MongoDB与其他数据源进行混合计算:A    B1    =mongo_open("mongodb://localhost:27017/test")    /连接MongDB2    =mongo_shell(A1,"emp.find({'$and':[{'Birthday':{'$gte':'"+string(begin)+"'}},{'Birthday':{'$lte':'"+string(end)+"'}}]},{_id:0})").fetch()    /查询某时间段的记录3    =A1.close()    /关闭MongoDB4    =myDB1.query("select   * from cities")    /获取mysql中表cities数据5    =A2.switch(CityID,A4:   CityID)    /外键关联6    =A5.new(EID,Dept,CityID.CityName:CityName,Name,Gender)    /创建结果集7    return   A6    /返回SQL支持SPL除了原生语法,还提供了相当于SQL92标准的SQL支持,可以使用SQL查询MongoDB了,比如前面的关联计算:A1    =mongo_open("mongodb://127.0.0.1:27017/test")2    =mongo_shell(A1,"c1.find()").fetch()3    =mongo_shell@x(A1,"c2.find()").fetch()4    $select s.* from {A2} as s left join {A3}   as r on s.user1=r.user1 and s.user2=r.user2 where r.income>0.3应用集成不仅如此,SPL提供了标准JDBC/ODBC等应用程序接口,集成调用很方便。如JDBC的使用:…Class.forName("com.esproc.jdbc.InternalDriver");Connection conn = DriverManager.getConnection("jdbc:esproc:local://");PrepareStatement st=con.prepareStatement("call splScript(?)"); // splScript为spl脚本文件名st.setObject(1,"California");st.execute();ResultSet rs = st.getResultSet();…有了这些功能,增强MongoDB的计算能力可不是说说而已,要不要下载试试?————————————————版权声明:本文为CSDN博主「石臻臻的杂货铺」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/u010634066/article/details/125854301
  • [问题求助] 在单个sql上开启smp是否会影响其他sql
    如图,在单个mapper的sql上添加set query_dop=-5;设置DN线程池是否为只在当前sql开启多线程数?会不会影响到其他sql?
  • [技术干货] 标准系列解读|服务商如何做好SQL审核与安全审计?
    本期接着上期的文章继续为大家解读《数据库服务能力成熟度模型》运维运营能力域的SQL审核与安全审计两个能力项,备份恢复与应急方案演练将在下一期文章中进行解读。《数据库服务能力成熟度模型》的整体框架如下图所示:《数据库服务能力成熟度模型》按照交付类型总体分为规划设计能力域、实施部署能力域和运维运营能力域,共包含27个能力项。每个能力项均从人员、工具、流程、制度、技术等维度,通过人员访谈、资料审查、工具演示等方式,对企业服务能力的评价从低到高依次划分为初始级、可重复级、稳健级、量化管理级和优化级五个等级。每个能力域的等级评定是由能力域所包含能力项的等级按照一定算法计算得出,每个能力项的等级评定是由该能力项五个等级的符合程度按照一定算法判定所得。简单来说,SQL审核能力是指为数据库服务方通过SQL审核平台或工具对未上线、已上线的SQL代码进行代码语法、算法的安全性和质量审核检查,提前发现SQL编写、表和索引设计等方面的隐患问题,推动开发部门提前进行规避性优化处理。SQL审核的主要过程描述如下:a) 数据库服务方与用户沟通SQL审核的管理流程,确定其中关键角色;b) 安装部署相关脚本或SQL审核工具;c) 确定需要审核的数据库和相关人员;d) 根据具体的审核需求,连接数据库采集SQL信息,或由用户提交审核信息,或者其他SQL来源;e) 查看SQL审核结果,发现SQL代码存在的隐患;f) 制定相关的优化建议并提交相关人员;g) 由相关人员对存在隐患的SQL代码进行整改;h) 对比整改前后的SQL运行情况,确认整改的执行性和优化的有效性。按照服务能力成熟度的差异划分,SQL审核能力要求如表1所示:表1 数据库服务能力成熟度-SQL审核能力等级标准评估要点:◆ SQL审核报告内容丰富度(SQL文本、违规情况、性能数据、优化建议等)、SQL审核流程、SQL审核模板等;◆ SQL审核服务体系,人员是否拥有SQL优化经验和对象设计经验,能否支撑从研发、测试、上线发布、运行维护全生命周期的SQL质量管控;◆ SQL审核工具/平台的功能丰富程度、易用性等。介绍完SQL审核后,接下来解读运维运营的第七个能力项:安全审计。安全审计是指数据库服务方根据需求方的安全审计要求,通过数据库自带的审计功能,或独立的安全审计工具、平台实现数据库安全审计功能,记录符合审计选项的操作记录。通过对用户访问数据库行为的记录、分析和汇报,帮助用户事后生成合规报告、事故追根溯源,同时加强内外部数据库行为记录,提高数据资产安全。根据公安行业标准《信息安全技术 数据库安全审计产品安全技术要求》定义,数据库安全审计产品是指对用户访问数据库的操作行为进行记录、分析并响应的产品。主要支持数据采集、设置采集策略、生成审计记录、安全告警、设置告警方式和内容、查询和统计审计记录、生成和导出报表、安全存储审计记录、会话分析、安全管理、审计日志等功能。安全审计的主要过程描述如下:a) 调研和需求分析:对需求方的安全审计需求进行调研和分析,了解需求方的管理规范、管理流程和审计需求;b) 制定方案:根据需求分析结果,制定安全审计方案。方案包括但不限于安全审计的配置操作手册、安全审计结果记录、安全审计结果呈现等;c) 安全审计实施:根据制定的安全审计方案,对安全审计进行在线或离线的启用、关闭等,并对相关的审计规则、告警规则等进行配置。如果有安全审计的辅助平台,要一并部署并保证能顺利执行;d) 安全审计验证:根据安全审计方案实施后,形成满足需求方的安全审计环境。与需求方一起选取代表性的业务场景,对安全审计功能进行验证,从而证明安全审计功能满足需求方的要求。按照服务能力成熟度的差异划分,安全审计的等级要求如表2所示:表2 数据库服务能力成熟度-安全审计能力等级标准评估要点:◆ 数据库安全审计工具功能完善性及易用性,审计对象和操作、告警方式和信息的丰富程度;◆ 人员的数据库安全审计经验、项目丰富度;◆ 安全审计方案、实施文档、管理规范等。《数据库服务能力成熟度模型》标准是由中国信息通信研究院依托通信标准化协会大数据技术标准推进委员会(CCSA TC601),联合云和恩墨、腾讯云、星环科技、新炬网络、中兴通讯、爱可生、华为云、华胜信泰、科蓝软件、浪潮云、金山云、迪思杰、万里开源、百度智能云等企业于2020年联合编制而成,标准共包括900多个评估点,成为国内数据库服务领域最权威的行业标准,目前已累计完成3批6家共11次评估工作,包括云和恩墨、星环科技、腾讯云、科蓝软件、中移苏研和京东科技,为行业遴选优质服务商提供有力依据。文章来源:大数据技术标准推进委员会 (如有侵权,请联系删除)
  • [技术干货] 吃透50个常用的SQL语句,面试趟过[转载]
    50个常用的sql语句Student(S#,Sname,Sage,Ssex) 学生表Course(C#,Cname,T#) 课程表SC(S#,C#,score) 成绩表Teacher(T#,Tname) 教师表问题:1、查询“001”课程比“002”课程成绩高的所有学生的学号; select a.S# from (select s#,score from SC where C#='001') a,(select s#,score from SC where C#='002') b where a.score>b.score and a.s#=b.s#;2、查询平均成绩大于60分的同学的学号和平均成绩;    select S#,avg(score)    from sc    group by S# having avg(score) >60;3、查询所有同学的学号、姓名、选课数、总成绩; select Student.S#,Student.Sname,count(SC.C#),sum(score) from Student left Outer join SC on Student.S#=SC.S# group by Student.S#,Sname4、查询姓“李”的老师的个数; select count(distinct(Tname)) from Teacher where Tname like '李%';5、查询没学过“叶平”老师课的同学的学号、姓名;    select Student.S#,Student.Sname    from Student     where S# not in (select distinct( SC.S#) from SC,Course,Teacher where SC.C#=Course.C# and Teacher.T#=Course.T# and Teacher.Tname='叶平');6、查询学过“001”并且也学过编号“002”课程的同学的学号、姓名; select Student.S#,Student.Sname from Student,SC where Student.S#=SC.S# and SC.C#='001'and exists( Select * from SC as SC_2 where SC_2.S#=SC.S# and SC_2.C#='002');7、查询学过“叶平”老师所教的所有课的同学的学号、姓名; select S#,Sname from Student where S# in (select S# from SC ,Course ,Teacher where SC.C#=Course.C# and Teacher.T#=Course.T# and Teacher.Tname='叶平' group by S# having count(SC.C#)=(select count(C#) from Course,Teacher where Teacher.T#=Course.T# and Tname='叶平'));8、查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名; Select S#,Sname from (select Student.S#,Student.Sname,score ,(select score from SC SC_2 where SC_2.S#=Student.S# and SC_2.C#='002') score2 from Student,SC where Student.S#=SC.S# and C#='001') S_2 where score2 <score;9、查询所有课程成绩小于60分的同学的学号、姓名; select S#,Sname from Student where S# not in (select Student.S# from Student,SC where S.S#=SC.S# and score>60);10、查询没有学全所有课的同学的学号、姓名;    select Student.S#,Student.Sname    from Student,SC    where Student.S#=SC.S# group by Student.S#,Student.Sname having count(C#) <(select count(C#) from Course);11、查询至少有一门课与学号为“1001”的同学所学相同的同学的学号和姓名;    select S#,Sname from Student,SC where Student.S#=SC.S# and C# in select C# from SC where S#='1001';12、查询至少学过学号为“001”同学所有一门课的其他同学学号和姓名;    select distinct SC.S#,Sname    from Student,SC    where Student.S#=SC.S# and C# in (select C# from SC where S#='001');13、把“SC”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩;    update SC set score=(select avg(SC_2.score)    from SC SC_2    where SC_2.C#=SC.C# ) from Course,Teacher where Course.C#=SC.C# and Course.T#=Teacher.T# and Teacher.Tname='叶平');14、查询和“1002”号的同学学习的课程完全相同的其他同学学号和姓名;    select S# from SC where C# in (select C# from SC where S#='1002')    group by S# having count(*)=(select count(*) from SC where S#='1002');15、删除学习“叶平”老师课的SC表记录;    Delect SC    from course ,Teacher     where Course.C#=SC.C# and Course.T#= Teacher.T# and Tname='叶平';16、向SC表中插入一些记录,这些记录要求符合以下条件:没有上过编号“003”课程的同学学号、2、    号课的平均成绩;    Insert SC select S#,'002',(Select avg(score)    from SC where C#='002') from Student where S# not in (Select S# from SC where C#='002');17、按平均成绩从高到低显示所有学生的“数据库”、“企业管理”、“英语”三门的课程成绩,按如下形式显示: 学生ID,,数据库,企业管理,英语,有效课程数,有效平均分    SELECT S# as 学生ID        ,(SELECT score FROM SC WHERE SC.S#=t.S# AND C#='004') AS 数据库        ,(SELECT score FROM SC WHERE SC.S#=t.S# AND C#='001') AS 企业管理        ,(SELECT score FROM SC WHERE SC.S#=t.S# AND C#='006') AS 英语        ,COUNT(*) AS 有效课程数, AVG(t.score) AS 平均成绩    FROM SC AS t    GROUP BY S#    ORDER BY avg(t.score) 18、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分    SELECT L.C# As 课程ID,L.score AS 最高分,R.score AS 最低分    FROM SC L ,SC AS R    WHERE L.C# = R.C# and        L.score = (SELECT MAX(IL.score)                      FROM SC AS IL,Student AS IM                      WHERE L.C# = IL.C# and IM.S#=IL.S#                      GROUP BY IL.C#)        AND        R.Score = (SELECT MIN(IR.score)                      FROM SC AS IR                      WHERE R.C# = IR.C#                  GROUP BY IR.C#                    );19、按各科平均成绩从低到高和及格率的百分数从高到低顺序    SELECT t.C# AS 课程号,max(course.Cname)AS 课程名,isnull(AVG(score),0) AS 平均成绩        ,100 * SUM(CASE WHEN isnull(score,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格百分数    FROM SC T,Course    where t.C#=course.C#    GROUP BY t.C#    ORDER BY 100 * SUM(CASE WHEN isnull(score,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) DESC20、查询如下课程平均成绩和及格率的百分数(用"1行"显示): 企业管理(001),马克思(002),OO&UML (003),数据库(004)    SELECT SUM(CASE WHEN C# ='001' THEN score ELSE 0 END)/SUM(CASE C# WHEN '001' THEN 1 ELSE 0 END) AS 企业管理平均分        ,100 * SUM(CASE WHEN C# = '001' AND score >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN C# = '001' THEN 1 ELSE 0 END) AS 企业管理及格百分数        ,SUM(CASE WHEN C# = '002' THEN score ELSE 0 END)/SUM(CASE C# WHEN '002' THEN 1 ELSE 0 END) AS 马克思平均分        ,100 * SUM(CASE WHEN C# = '002' AND score >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN C# = '002' THEN 1 ELSE 0 END) AS 马克思及格百分数        ,SUM(CASE WHEN C# = '003' THEN score ELSE 0 END)/SUM(CASE C# WHEN '003' THEN 1 ELSE 0 END) AS UML平均分        ,100 * SUM(CASE WHEN C# = '003' AND score >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN C# = '003' THEN 1 ELSE 0 END) AS UML及格百分数        ,SUM(CASE WHEN C# = '004' THEN score ELSE 0 END)/SUM(CASE C# WHEN '004' THEN 1 ELSE 0 END) AS 数据库平均分        ,100 * SUM(CASE WHEN C# = '004' AND score >= 60 THEN 1 ELSE 0 END)/SUM(CASE WHEN C# = '004' THEN 1 ELSE 0 END) AS 数据库及格百分数 FROM SC21、查询不同老师所教不同课程平均分从高到低显示 SELECT max(Z.T#) AS 教师ID,MAX(Z.Tname) AS 教师姓名,C.C# AS 课程ID,MAX(C.Cname) AS 课程名称,AVG(Score) AS 平均成绩    FROM SC AS T,Course AS C ,Teacher AS Z    where T.C#=C.C# and C.T#=Z.T# GROUP BY C.C# ORDER BY AVG(Score) DESC22、查询如下课程成绩第 3 名到第 6 名的学生成绩单:企业管理(001),马克思(002),UML (003),数据库(004)    [学生ID],[学生姓名],企业管理,马克思,UML,数据库,平均成绩    SELECT DISTINCT top 3      SC.S# As 学生学号,        Student.Sname AS 学生姓名 ,      T1.score AS 企业管理,      T2.score AS 马克思,      T3.score AS UML,      T4.score AS 数据库,      ISNULL(T1.score,0) + ISNULL(T2.score,0) + ISNULL(T3.score,0) + ISNULL(T4.score,0) as 总分      FROM Student,SC LEFT JOIN SC AS T1                      ON SC.S# = T1.S# AND T1.C# = '001'            LEFT JOIN SC AS T2                      ON SC.S# = T2.S# AND T2.C# = '002'            LEFT JOIN SC AS T3                      ON SC.S# = T3.S# AND T3.C# = '003'            LEFT JOIN SC AS T4                      ON SC.S# = T4.S# AND T4.C# = '004'      WHERE student.S#=SC.S# and      ISNULL(T1.score,0) + ISNULL(T2.score,0) + ISNULL(T3.score,0) + ISNULL(T4.score,0)      NOT IN      (SELECT            DISTINCT            TOP 15 WITH TIES            ISNULL(T1.score,0) + ISNULL(T2.score,0) + ISNULL(T3.score,0) + ISNULL(T4.score,0)      FROM sc            LEFT JOIN sc AS T1                      ON sc.S# = T1.S# AND T1.C# = 'k1'           LEFT JOIN sc AS T2                      ON sc.S# = T2.S# AND T2.C# = 'k2'            LEFT JOIN sc AS T3                      ON sc.S# = T3.S# AND T3.C# = 'k3'            LEFT JOIN sc AS T4                      ON sc.S# = T4.S# AND T4.C# = 'k4'      ORDER BY ISNULL(T1.score,0) + ISNULL(T2.score,0) + ISNULL(T3.score,0) + ISNULL(T4.score,0) DESC);23、统计列印各科成绩,各分数段人数:课程ID,课程名称,[100-85],[85-70],[70-60],[ <60]    SELECT SC.C# as 课程ID, Cname as 课程名称        ,SUM(CASE WHEN score BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS [100 - 85]        ,SUM(CASE WHEN score BETWEEN 70 AND 85 THEN 1 ELSE 0 END) AS [85 - 70]        ,SUM(CASE WHEN score BETWEEN 60 AND 70 THEN 1 ELSE 0 END) AS [70 - 60]        ,SUM(CASE WHEN score < 60 THEN 1 ELSE 0 END) AS [60 -]    FROM SC,Course    where SC.C#=Course.C#    GROUP BY SC.C#,Cname;24、查询学生平均成绩及其名次      SELECT 1+(SELECT COUNT( distinct 平均成绩)              FROM (SELECT S#,AVG(score) AS 平均成绩                      FROM SC                  GROUP BY S#                  ) AS T1            WHERE 平均成绩 > T2.平均成绩) as 名次,      S# as 学生学号,平均成绩    FROM (SELECT S#,AVG(score) 平均成绩            FROM SC        GROUP BY S#        ) AS T2    ORDER BY 平均成绩 desc;25、查询各科成绩前三名的记录:(不考虑成绩并列情况)      SELECT t1.S# as 学生ID,t1.C# as 课程ID,Score as 分数      FROM SC t1      WHERE score IN (SELECT TOP 3 score              FROM SC              WHERE t1.C#= C#            ORDER BY score DESC              )      ORDER BY t1.C#;26、查询每门课程被选修的学生数 select c#,count(S#) from sc group by C#;27、查询出只选修了一门课程的全部学生的学号和姓名 select SC.S#,Student.Sname,count(C#) AS 选课数 from SC ,Student where SC.S#=Student.S# group by SC.S# ,Student.Sname having count(C#)=1;28、查询男生、女生人数    Select count(Ssex) as 男生人数 from Student group by Ssex having Ssex='男';    Select count(Ssex) as 女生人数 from Student group by Ssex having Ssex='女';29、查询姓“张”的学生名单    SELECT Sname FROM Student WHERE Sname like '张%';30、查询同名同性学生名单,并统计同名人数 select Sname,count(*) from Student group by Sname having count(*)>1;;31、1981年出生的学生名单(注:Student表中Sage列的类型是datetime)    select Sname, CONVERT(char (11),DATEPART(year,Sage)) as age    from student    where CONVERT(char(11),DATEPART(year,Sage))='1981';32、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列    Select C#,Avg(score) from SC group by C# order by Avg(score),C# DESC ;33、查询平均成绩大于85的所有学生的学号、姓名和平均成绩    select Sname,SC.S# ,avg(score)    from Student,SC    where Student.S#=SC.S# group by SC.S#,Sname having    avg(score)>85;34、查询课程名称为“数据库”,且分数低于60的学生姓名和分数    Select Sname,isnull(score,0)    from Student,SC,Course    where SC.S#=Student.S# and SC.C#=Course.C# and Course.Cname='数据库'and score <60;35、查询所有学生的选课情况;    SELECT SC.S#,SC.C#,Sname,Cname    FROM SC,Student,Course    where SC.S#=Student.S# and SC.C#=Course.C# ;36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数;    SELECT distinct student.S#,student.Sname,SC.C#,SC.score    FROM student,Sc    WHERE SC.score>=70 AND SC.S#=student.S#;37、查询不及格的课程,并按课程号从大到小排列    select c# from sc where scor e <60 order by C# ;38、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名;    select SC.S#,Student.Sname from SC,Student where SC.S#=Student.S# and Score>80 and C#='003';39、求选了课程的学生人数    select count(*) from sc;40、查询选修“叶平”老师所授课程的学生中,成绩最高的学生姓名及其成绩    select Student.Sname,score    from Student,SC,Course C,Teacher    where Student.S#=SC.S# and SC.C#=C.C# and C.T#=Teacher.T# and Teacher.Tname='叶平' and SC.score=(select max(score)from SC where C#=C.C# );41、查询各个课程及相应的选修人数    select count(*) from sc group by C#;42、查询不同课程成绩相同的学生的学号、课程号、学生成绩 select distinct A.S#,B.score from SC A ,SC B where A.Score=B.Score and A.C# <>B.C# ;43、查询每门功成绩最好的前两名    SELECT t1.S# as 学生ID,t1.C# as 课程ID,Score as 分数      FROM SC t1      WHERE score IN (SELECT TOP 2 score              FROM SC              WHERE t1.C#= C#            ORDER BY score DESC              )      ORDER BY t1.C#;44、统计每门课程的学生选修人数(超过10人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,查询结果按人数降序排列,若人数相同,按课程号升序排列     select C# as 课程号,count(*) as 人数    from sc     group by C#    order by count(*) desc,c# 45、检索至少选修两门课程的学生学号    select S#     from sc     group by s#    having count(*) > = 246、查询全部学生都选修的课程的课程号和课程名    select C#,Cname     from Course     where C# in (select c# from sc group by c#) 47、查询没学过“叶平”老师讲授的任一门课程的学生姓名    select Sname from Student where S# not in (select S# from Course,Teacher,SC where Course.T#=Teacher.T# and SC.C#=course.C# and Tname='叶平');48、查询两门以上不及格课程的同学的学号及其平均成绩    select S#,avg(isnull(score,0)) from SC where S# in (select S# from SC where score <60 group by S# having count(*)>2)group by S#;49、检索“004”课程分数小于60,按分数降序排列的同学学号    select S# from SC where C#='004'and score <60 order by score desc;50、删除“002”同学的“001”课程的成绩delete from Sc where S#='001'and C#='001';————————————————版权声明:本文为CSDN博主「软件质量保障」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/csd11311/article/details/125750653
总条数:865 到第 页
上滑加载中