• [SQL] 导出pg_default_acl表的alter default privileges语句,参考方式
    pg_default_acl表原始数据select * from pg_default_acl;pg_default_acl表简单处理sqlSELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS "Granter", n.nspname AS "Schema", CASE d.defaclobjtype WHEN 'r' THEN 'table' WHEN 'S' THEN 'sequence' WHEN 'f' THEN 'function' WHEN 'T' THEN 'type' END AS "Type", pg_catalog.array_to_string(d.defaclacl, E', ') AS "Access privileges" FROM pg_catalog.pg_default_acl d LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace ORDER BY 1, 2, 3;1、先建立一个权限的映射表create table public.ysw ( prototype varchar(1), aim varchar(10) ); insert into ysw values('r','select'); insert into ysw values('a','insert');2、创建一个函数转化格式,比如将权限ra转化为select,insert形式create or replace function fun_ysw(varchar) returns varchar as $$ declare re varchar :=''; tmp varchar := ''; fr varchar :=''; i int := 1; length int := char_length($1); begin while i<=length loop select substring($1,i,1) into fr; select aim into tmp from ysw where prototype = fr; re :=concat(re,tmp); if i<length then re :=concat(re,','); end if; i :=i+1; end loop; return re; end; $$ LANGUAGE plpgsql;3、最终查询sql示例模板:alter default privileges for user 原始 in schema 模式 grant 拼接权限 on 类型 to 用户可能多个;查询sqlSELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS "granter", n.nspname AS "schema", CASE d.defaclobjtype WHEN 'r' THEN 'tables' WHEN 'S' THEN 'sequences' WHEN 'f' THEN 'functions' WHEN 'T' THEN 'types' END AS "Type", d.defaclacl, fun_ysw(to_char(regexp_substr(d.defaclacl[1]::text, '(?<=\=).*?(?=\/)'))) as right, rtrim(regexp_replace(concat(pg_catalog.array_to_string(d.defaclacl, E','),','), '\=.*?(?=\,)','','g'),',') as usernames FROM pg_catalog.pg_default_acl d LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace ORDER BY 1, 2, 3;最后可以按需求拼接,,要根据数据状况进行适当修改
  • [热门活动] 【数仓专题直播有奖提问】DTSE Tech Talk 技术直播 NO.34:看直播提问题赢华为云定制长袖卫衣、华为云定制Polo衫等好礼!
    中奖结果公示感谢各位小伙伴参与本次活动,本次活动获奖名单如下:请各位获奖的伙伴在6月30日之前点击此处填写收货地址,如逾期未填写视为弃奖。再次感谢各位小伙伴参与本次活动,欢迎关注华为云DTSE Tech Talk 技术直播更多活动~直播简介【直播主题】数仓过载不用愁,资源管理帮分忧【直播时间】2023年6月28日 16:30-18:00【直播专家】周孟韬 华为云EI DTSE技术布道师【直播简介】面对磁盘空间、内存、CPU等资源过载问题,GaussDB(DWS)资源管理机制来支招,本期直播华为云数仓专家孟韬老师带您全面了解GaussDB(DWS)的资源管理机制,让数仓过载烦恼不再,把“烂”SQL牢牢关进笼子里,让我们的管控技术为您的业务保驾护航。直播链接:cid:link_2活动介绍【互动方式】直播前您可以在本帖留下您疑惑的问题,专家会在直播时为您解答。直播后您可以继续在本帖留言,与专家互动交流。我们会在全部活动结束后对参与互动的用户进行评选。【活动时间】即日起—2023年6月28日【奖励说明】评奖规则:活动1:直播期间在直播间提出与直播内容相关的问题,对专家评选为优质问题的开发者进行奖励。奖品:华为云定制长袖卫衣活动2:在本帖提出与直播内容相关的问题,由专家在所有互动贴中选出最优问题贴的开发者进行奖励。奖品:华为云定制Polo衫更多直播活动直播互动有礼:官网直播间发口令“华为云 DTSE”抽华为云云宝公仔、填写问卷抽华为云定制无线鼠标等好礼;直播过程中提问,评选优质问题送华为云定制长袖卫衣。分享问卷有礼 :邀请5位朋友以上完成问卷即可获得华为云定制棒球帽。戳我填问卷》》老观众专属福利:连续报名并观看DTT直播3期以上抽送华为云DTT定制T恤。【注意事项】1、所有参与活动的问题,如发现为复用他人内容,则取消获奖资格。2、为保证您顺利领取活动奖品,请您在活动公示奖项后2个工作日内私信提前填写奖品收货信息,如您没有填写,视为自动放弃奖励。3、活动奖项公示时间截止2023年6月30日,如未反馈邮寄信息视为弃奖。本次活动奖品将于奖项公示后30个工作日内统一发出,请您耐心等待。4、活动期间同类子活动每个ID(同一姓名/电话/收货地址)只能获奖一次,若重复则中奖资格顺延至下一位合格开发者,仅一次顺延。5、如活动奖品出现没有库存的情况,华为云工作人员将会替换等价值的奖品,获奖者不同意此规则视为放弃奖品。6、其他事宜请参考【华为云社区常规活动规则】。
  • [技术干货] 为什么是update table_name 而不是update from table_name
    在 SQL 语言中,UPDATE 语句用于修改一个或多个表格中的数据行。一般而言,UPDATE 语句中需要指定两个主要部分:要更新的数据表和要更新的实际数据内容。通常情况下,我们使用如下形式的 UPDATE 语句:UPDATE table_name SET column1 = value1, column2 = value2 WHERE conditions;其中,table_name 表示要更新的数据表名称。可以发现,在这个 UPDATE 语句的主体语句中并没有使用 FROM 关键字,而是直接使用了表格名称来表示要更新哪个数据表格中的数据行。事实上,UPDATE 语句不需要使用 FROM 子句来指定数据表格。这是因为 UPDATE 语句只向单个数据表执行数据行更新操作,不像 DELETE 语句那样需要从多个表中获取记录。当然,如果你需要跨越多个表格联合查询或过滤数据以完成更新操作,那么就需要使用FROM 子句了。例如,下面这个例子演示了如何使用 FROM 子句来聚合更新多个表格中符合条件的记录:UPDATE table1 SET column1 = value1 FROM table1 INNER JOIN table2 ON condition1 WHERE condition2;综上所述,UPDATE 语句不需要使用 FROM 子句来指定要更新的数据表格。这种语法设计可以简化代码,并且符合 SQL 语言设计的一般惯例。只有在需要联表操作时,才需要使用 FROM 子句来指定多个表格。
  • [数据库类] 鸿蒙系统2.0 不支持sqlite中的over() 函数吗
    我发现同样的程序,同样的sql,在小米等android设备上是可以执行的,但是在鸿蒙2.0上却执行失败,譬如select count() over(),在鸿蒙上就执行失败了,而select count()成功了,难道鸿蒙不支持over()函数的实现?
  • [其他] GaussDB(DWS) FULL JOIN查询语句优化
    SQL语句中使用了FULL JOIN,部分语句如下: and je."城市(city)" = coalesce(kc."城市(city)", med."城市(city)", t."城市(city)", check_nomatch."城市(city)") full outer join ( select "月份(data_month)", coalesce("经销商编码(dealer_code)", '-') as "经销商编码(dealer_code)",查看查询计划走了Nested Loop Left Join+Index索引扫描,计划如下: 1 | -> Limit | 18 | | 986 | 124394168.04 2 | -> Streaming (type: GATHER) | 18 | | 986 | 124394168.04 3 | -> Limit | 18 | 1MB | 986 | 124394154.04 4 | -> HashAggregate | 18 | 16MB | 986 | 124394154.04 5 | -> Streaming(type: REDISTRIBUTE) | 19 | 2MB | 410 | 124394153.74 6 | -> Nested Loop Left Join (7, 95) | 19 | 1MB | 410 | 124394153.08 ……………………………………………………………………………………………………………………………………………………………… 90 | -> Hash | 13812 | 16MB | 295 | 249.09 91 | -> Subquery Scan on tar | 13812 | 1MB | 295 | 249.09 92 | -> HashAggregate | 13812 | 16MB | 108 | 226.07 93 | -> Streaming(type: REDISTRIBUTE) | 13812 | 2MB | 44 | 168.52 94 | -> Seq Scan on fact_dm_sales_target_jetta | 13812 | 1MB | 44 | 73.02 95 | -> Index Scan using dim_pub_erp_dealer_info_daily_pk on dim_pub_erp_dealer_info_daily | 1 | 1MB | 50 | 0.39 该语句通过full join优化重写,走了Nested Loop+Index索引扫描,执行性能可以优化。建议优化方案:全局关闭enable_index_nestloop参数,让查询计划不走Nested Loop+Index索引扫描。
  • [技术干货] SQL创建视图的注意事项及说明
    视图的创建和注意事项如何创建视图及注意事项创建视图图的基本语法:1234CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS<SELECT语句>from  表名group by 列名;-- 该语句可以选择或者不写该语句,两者的区别就是是否有汇总注意事项:视图名称后面的列的数量必须与select 语句里面选择的列的数量一致;否则会提示错误;当你创建了一个视图后(同个视图名字),若需要对视图语句进行修改的话,需要先删除旧的视图,否则会提示已有视图;select 语句里面的列与视图里面的列是一一对应的,视图里面的列名可以根据需要自定义命名;删除视图语法: drop view 视图名称例子:案例1. with group by12345678drop view profit;create view profit (种类,售价, 进价,利润)Asselect product_type,sale_price,purchase_price,sale_price - purchase_price as profitfrom productgroup by product_type;select * from profit;结果如下:案例2: without group by123456drop view profit1;create view profit1 (种类,售价, 进价,利润)Asselect product_type,sale_price,purchase_price,sale_price - purchase_price as profitfrom product; select * from profit1;结果如下:修改视图结构修改视图结构的基本语法如下:1234567ALTER VIEW <视图名> AS <SELECT语句>-- 例如:ALTER VIEW profit    AS        SELECT product_type, sale_price          FROM Product         WHERE regist_date > '2009-09-11';mysql视图的作用(详细)测试表:user有id,name,age,sex字段测试表:goods有id,name,price字段测试表:ug有id,userid,goodsid字段视图的作用实在是太强大了,以下是我体验过的好处:作用一提高了重用性,就像一个函数。如果要频繁获取user的name和goods的name。就应该使用以下sql语言。示例:        1select a.name as username, b.name as goodsname from user as a, goods as b, ug as c where a.id=c.userid and c.goodsid=b.id;但有了视图就不一样了,创建视图other。示例:        1create view other as select a.name as username, b.name as goodsname from user as a, goods as b, ug as c where a.id=c.userid and c.goodsid=b.id;创建好视图后,就可以这样获取user的name和goods的name。示例:        1select * from other;以上sql语句,就能获取user的name和goods的name了。作用二对数据库重构,却不影响程序的运行。假如因为某种需求,需要将user拆房表usera和表userb,该两张表的结构如下:测试表:usera有id,name,age字段测试表:userb有id,name,sex字段这时如果php端使用sql语句:select * from user;那就会提示该表不存在,这时该如何解决呢。解决方案:创建视图。以下sql语句创建视图:1create view user as select a.name,a.age,b.sex from usera as a, userb as b where a.name=b.name;以上假设name都是唯一的。此时php端使用sql语句:select * from user;就不会报错什么的。这就实现了更改数据库结构,不更改脚本程序的功能了。作用三提高了安全性能。可以对不同的用户,设定不同的视图。例如:某用户只能获取user表的name和age数据,不能获取sex数据。则可以这样创建视图。示例如下:1create view other as select a.name, a.age from user as a;这样的话,使用sql语句:select * from other; 最多就只能获取name和age的数据,其他的数据就获取不了了。作用四让数据更加清晰。想要什么样的数据,就创建什么样的视图。经过以上三条作用的解析,这条作用应该很容易理解了吧转载自https://www.jb51.net/article/274547.htm
  • [问题求助] GaussDB集中式和分布式在SQL方面具体有多少差异,官方有没有整理相关性文档
    1.GaussDB集中式和分布式在SQL方面具体有多少差异,官方有没有整理相关性文档2.如有文档,在哪里可以查阅学习。3. GaussDB集中式和Oracle在SQL方面具体有多少差异,官方有没有整理相关性文档?如有文档,在哪里查阅学习?
  • [其他] GaussDB(DWS) Java自定义函数常见问题
    1、问题现象 用户使用Java编写了自定义的函数,函数在调用时返回结果为空,或者执行时报错。 2、问题定位过程 自定义函数UDF的日志路径在$GAUSSLOG/cm/cm_agent/pg_log,通过查看日志可以找到报错信息。(1)执行函数时报错,报错信息为security operation is not allowed 。 FATAL:  java.lang.ExceptionInInitializerError                 at sun.security.jca.GetInstance.getInstance(GetInstance.java:156)                 at java.security.Security.getImpl(Security.java:695)                 at java.security.MessageDigest.getInstance(MessageDigest.java:170)                 at String2Sha1.stringToSHA1(String2Sha1.java:14)         Caused by : security operation is not allowed.                 at org.postgresql.pljava.internal.Backend$2.assertPermission(Backend.java:359)                 at org.postgresql.pljava.internal.Backend$PLJavaSecurityManager.nonRecursiveCheck(Backend.java:135)                 at org.postgresql.pljava.internal.Backend$PLJavaSecurityManager.checkPermission(Backend.java:111)                 at java.security.Security.getProperty(Security.java:760)                 at sun.security.jca.ProviderList.(ProviderList.java:166)                 at sun.security.jca.ProviderList.(ProviderList.java:56)                 at sun.security.jca.ProviderList$2.run(ProviderList.java:86)                 at sun.security.jca.ProviderList$2.run(ProviderList.java:84)                 at java.security.AccessController.doPrivileged(Native Method)                 at sun.security.jca.ProviderList.fromSecurityProperties(ProviderList.java:83)                 at sun.security.jca.Providers.(Providers.java:54)                 at sun.security.jca.GetInstance.getInstance(GetInstance.java:156)                 at java.security.Security.getImpl(Security.java:695)                 at java.security.MessageDigest.getInstance(MessageDigest.java:170)                 at String2Sha1.stringToSHA1(String2Sha1.java:14)  如果出现上述报错,表示javaudf函数执行过程中禁止Security配置修改(SecurityPermission权限)。  (2)执行函数时报错,异常信息为reflection is not allowed postgres=# select SM4EncDefault('DWS'); ERROR:  UDF Error:java.lang.InternalError: cannot create instance of org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings : java.lang.SecurityException: reflection is not allowed.         at org.bouncycastle.jce.provider.BouncyCastleProvider.loadServiceClass(Unknown Source)         at org.bouncycastle.jce.provider.BouncyCastleProvider.loadAlgorithms(Unknown Source)         at org.bouncycastle.jce.provider.BouncyCastleProvider.setup(Unknown Source)         at org.bouncycastle.jce.provider.BouncyCastleProvider.access$000(Unknown Source)         at org.bouncycastle.jce.provider.BouncyCastleProvider$1.run(Unknown Source)         at java.security.AccessController.doPrivileged(Native Method)         at org.bouncycastle.jce.provider.BouncyCastleProvider.(Unknown Source)         at com.wxtool.ChinaCipherSM4Base.(ChinaCipherSM4Base.java:28)         at com.wxtool.ChinaCipher.SM4Enc(ChinaCipher.java:188)         at com.wxtool.ChinaCipher.SM4EncDefault(ChinaCipher.java:218)         at encrypt.SM4EncDefault.evaluate(SM4EncDefault.java:24) CONTEXT:  referenced column: sm4encdefault  如果出现上述报错,表示javaudf函数执行过程中禁用了反射(ReflectPermission权限)。  (3)执行函数时报错NoSuchAlgorithmException  java.security.NoSuchAlgorithmException: SHA-1 MessageDigest not available         at sun.security.jca.GetInstance.getInstance(GetInstance.java:159)         at java.security.Security.getImpl(Security.java:695)         at java.security.MessageDigest.getInstance(MessageDigest.java:170)  SHA-1算法在Java代码中是通过反射方式获取的,因此这是因为javaudf函数执行过程中禁用了反射(ReflectPermission权限)造成的。  (4)执行函数时报错信息为java.security.InvalidKeyException: No installed provider supports this key,这是因为Java中类的加载是由classloader完成的,  javaudf函数执行过程中禁止自定义classLoder(createClassLoader权限)引起了报错。  3、问题解决方案  以上为 Java自定义函数常见的问题,解决方法是设置javaudf_disable_feature参数,去掉其中的security, reflection,classloader  设置方法为:  gs_guc reload -Z coordinator -Z datanode -N all -I all -c "javaudf_disable_feature='extdir, hadoop, loadlibrary, net, socket, access_declared_members'"  ​ 
  • [技术干货] 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迁移] 从navicat导出的表创建语句,在DWS的SQL窗口运行,不能识别单引号和反向单引号
    报错见上图。还有一种反向单引号,也不能识别,见下图:
  • [其他] GaussDB (DWS) 部分CN查询慢问题定位指南
    问题现象某国网业务主要连接GaussDB(DWS)的一个CN(cn5001),平常毫秒级的查询出现了偶发劣化到秒级的现象,在其他的CN上执行SQL语句,性能是正常的。语句的查询计划显示GATHER算子慢,需要3秒多。问题影响业务反馈SQL执行速度慢,任务产生积压cn5001上的活跃会话数不断增加,大量业务处于waiting in global queue的排队状态排查过程1. 按照GaussDB(DWS)性能问题的排查思路,查看活跃会话视图和等待视图,排查是否有明显的瓶颈点。2. 根据CN5001的进程号,通过ps命令查询进程,看CN进程是否在不断启动新的进程。找CN进程号命令为:ps -ef | grep coo通过进程PID找是否在启动进程的方法:ps -ef | grep 上一步找到的进程PID,显示进程号为23741的CN在不断启动新的进程。3. 查看该CN的pg_log日志是否有报错。CN的日志显示有too many connections for role "xxxx"的报错,并通过/opt/huawei/snas/bin/snas_cm_cmd命令来上报告警信息。解决方案将CN5001上报告警的命令/opt/huawei/snas/bin/snas_cm_cmd重命名,暂停上报告警后,验证语句的执行性能恢复正常取消对用户的连接数限制,避免频繁触发告警问题原因对用户设置了30个连接数的限制,当前该用户的连接数已达到30个,此时用户新建连接会触发报错too many connections for role "xxxx"报错会触发一个用户连接数过多的告警,这个告警通过执行/opt/huawei/snas/bin/snas_cm_cmd命令来进行上报。snas_cm_cmd命令是通过gaussdb进程通过fork新的进程的方式来调用。用户连接数过多时,告警频繁上报,进程的不断启动导致GaussDB进程的性能波动大。
  • [技术干货] 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个小时内执行完成,问题得到解决。查询计划如下图所示: