云服务器内容精选

  • 获取函数返回值 JDBC调用函数时获取返回值,以下示例展示返回值类型为bit和float8两种数据类型,其他数据类型可参考本示例。 代码运行的前提条件:根据实际情况添加gaussdbjdbc.jar包(例如用户使用IDE执行代码,则需要在本地IDE添加gaussdbjdbc.jar包)。 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。// $ip、$port、database需要用户自行修改。import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;import java.sql.CallableStatement;import java.sql.SQLException;import java.sql.PreparedStatement;import java.sql.Types;public class Type { public static void main(String[] args) throws SQLException { String driver = "com.huawei.gaussdb.jdbc.Driver"; String username = System.getenv("EXAMPLE_USERNAME_ENV"); String passwd = System.getenv("EXAMPLE_PASSWORD_ENV"); String sourceURL = "jdbc:gaussdb://$ip:$port/database"; Connection conn = null; try { // 加载数据库驱动。 Class.forName(driver).newInstance(); } catch (Exception e) { e.printStackTrace(); } try { // 以非加密方式创建数据库连接。 conn = DriverManager.getConnection(sourceURL, username, passwd); System.out.println("Connection succeed!"); } catch (Exception e) { e.printStackTrace(); } // 建表。 String createsql = "create table if not exists t_bit(col_bit bit)"; Statement stmt = conn.createStatement(); stmt.execute(createsql); stmt.close(); // bit类型使用示例,注意此处bit类型取值范围[0,1]。 Statement st = conn.createStatement(); String sqlstr = "create or replace function fun_1()\n" + "returns bit AS $$\n" + "select col_bit from t_bit limit 1;\n" + "$$\n" + "LANGUAGE SQL;"; st.execute(sqlstr); CallableStatement c = conn.prepareCall("{ ? = call fun_1() }"); // 注册输出类型,位串类型。 c.registerOutParameter(1, Types.BIT); c.execute(); // 使用Boolean类型获取结果。 System.out.println(c.getBoolean(1)); // float8类型使用示例。 st.execute("create table if not exists t_float(col1 float8)"); PreparedStatement pstm = conn.prepareStatement("insert into t_float values(?)"); pstm.setDouble(1, 123456.123); pstm.execute(); pstm.close(); // 函数返回值为float8的使用示例。 st.execute( "create or replace function func_float() " + "return float8 " + "as declare " + "var1 float8; " + "begin " + " select col1 into var1 from t_float limit 1; " + " return var1; " + "end;"); CallableStatement cs = conn.prepareCall("{? = call func_float()}"); cs.registerOutParameter(1, Types.DOUBLE); cs.execute(); System.out.println(cs.getDouble(1)); st.close(); // 关闭数据库连接。 try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }} 上述示例的运行结果为: Connection succeed!false123456.123 父主题: 典型应用开发示例
  • 内容介绍 本文主要描述ClickHouse数据管理全生命周期过程中,数据库规划、建模设计、开发、调优、运维的规则建议和指导。 通过这些约束和建议,指导开发者在ClickHouse数据库开发使用过程中能够最大化发挥数据库的优势,保障ClickHouse数据库高性能、稳定可靠运行。用户可更专注于上层业务,释放数据更大的价值。 表1 ClickHouse设计规范说明 项目 描述 数据库规划 集群业务规划、容量规划、数据分布。 数据库设计 Database设计、宽表设计、分布式表设计、本地表设计、分区设计、索引设计、物化视图设计。 数据库开发 简单查询、聚合查询、join查询、数据增/删/改等SQL开发。 数据库调优 调优思路、参数调优、系统调优、SQL改写调优。 数据库运维 监控、告警、日志、系统表/视图。
  • RDD多次使用时,建议将RDD持久化 RDD在默认情况下的存储级别是StorageLevel.NONE,即既不存磁盘也不放在内存中,如果某个RDD需要多次使用,可以考虑将该RDD持久化,方法如下: 调用spark.RDD中的cache()、persist()、persist(newLevel:StorageLevel)函数均可将RDD持久化,cache()和persist()都是将RDD的存储级别设置为StorageLevel.MEMORY_ONLY,persist(newLevel:StorageLevel)可以为RDD设置其他存储级别,但是要求调用该方法之前RDD的存储级别为StorageLevel.NONE或者与newLevel相同,也就是说,RDD的存储级别一旦设置为StorageLevel.NONE之外的级别,则无法改变。 如果想要将RDD去持久化,那么可以调用unpersist(blocking:Boolean = true),该函数功能如下: 将该RDD从持久化列表中移除,RDD对应的数据进入可回收状态; 将RDD的存储级别重新设置为StorageLevel.NONE。
  • 在对性能要求比较高的场景下,可以使用Kryo优化序列化性能 Spark提供了两种序列化实现: org.apache.spark.serializer.KryoSerializer:性能好,兼容性差 org.apache.spark.serializer.JavaSerializer:性能一般,兼容性好 使用:conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") 为什么不默认使用Kryo序列化? Spark默认使用的是Java的序列化机制,也就是ObjectOutputStream/ObjectInputStream API来进行序列化和反序列化。但是Spark同时支持使用Kryo序列化库,Kryo序列化类库的性能比Java序列化类库的性能要高很多。官方介 绍,Kryo序列化机制比Java序列化机制,性能高10倍左右。Spark之所以默认没有使用Kryo作为序列化类库,是因为Kryo要求要注册所有需要进行序列化的自定义类型,因此对于开发者来说,这种方式比较麻烦。
  • 在业务情况允许的情况下使用高性能算子 使用reduceByKey/aggregateByKey替代groupByKey。 所谓的map-side预聚合,说的是在每个节点本地对相同的key进行一次聚合操作,类似于MapReduce中的本地combiner。 map-side预聚合之后,每个节点本地就只会有一条相同的key,因为多条相同的key都被聚合起来了。其他节点在拉取所有节点上的相同key时,就会大大减少需要拉取的数据数量,从而也就减少了磁盘IO以及网络传输开销。通常来说,在可能的情况下,建议使用reduceByKey或aggregateByKey算子来替代掉groupByKey算子。因为reduceByKey和aggregateByKey算子都会使用用户自定义的函数对每个节点本地的相同key进行预聚合。而groupByKey算子是不会进行预聚合的,全量的数据会在集群的各个节点之间分发和传输,性能相对来说比较差。 使用mapPartitions替代普通map。 mapPartitions类的算子,一次函数调用会处理一个partition所有的数据,而不是一次函数调用处理一条,性能相对来说会高一些。 但是有的时候,使用mapPartitions会出现OOM(内存溢出)的问题。因为单次函数调用就要处理掉一个partition所有的数据,如果内存不够,垃圾回收时是无法回收掉太多对象的,很可能出现OOM异常。所以使用这类操作时要慎重! 使用filter之后进行coalesce操作。 通常对一个RDD执行filter算子过滤掉RDD中较多数据后(比如30%以上的数据),建议使用coalesce算子,手动减少RDD的partition数量,将RDD中的数据压缩到更少的partition中去。因为filter之后,RDD的每个partition中都会有很多数据被过滤掉,此时如果照常进行后续的计算,其实每个task处理的partition中的数据量并不是很多,有一点资源浪费,而且此时处理的task越多,可能速度反而越慢。因此用coalesce减少partition数量,将RDD中的数据压缩到更少的partition之后,只要使用更少的task即 可处理完所有的partition。在某些场景下,对于性能的提升会有一定的帮助。 使用repartitionAndSortWithinPartitions替代repartition与sort类操作。 repartitionAndSortWithinPartitions是Spark官网推荐的一个算子,官方建议,如果需要在 repartition重分区之后,还要进行排序,建议直接使用repartitionAndSortWithinPartitions 算子。因为该算子 可以一边进行重分区的shuffle操作,一边进行排序。shuffle与sort两个操作同时进行,比先shuffle再sort来说,性能可能是要高的。 使用foreachPartitions替代foreach。 原理类似于“使用mapPartitions替代map”,也是一次函数调用处理一个partition的所有数据,而不是一次函数调用处理一条数 据。在实践中发现,foreachPartitions类的算子,对性能的提升还是很有帮助的。比如在foreach函数中,将RDD中所有数据写 MySQL,那么如果是普通的foreach算子,就会一条数据一条数据地写,每次函数调用可能就会创建一个数据库连接,此时就势必会频繁地创建和销毁数据库连接,性能是非常低下;但是如果用foreachPartitions算子一次性处理一个partition的数据,那么对于每个 partition,只要创建一个数据库连接即可,然后执行批量插入操作,此时性能是比较高的。
  • UDF管理 建议由管理员创建永久UDF,避免每次使用时都去add jar,和重新定义UDF。 Hive的UDF会有一些默认属性,比如“deterministic”默认为“true”(同一个输入会返回同一个结果),“stateful”(是否有状态,默认为“true”)。当用户实现的自定义UDF内部实现了汇总等,需要在类上加上相应的注解,例如如下类: @UDFType(deterministic = false)Public class MyGenericUDAFEvaluator implements Closeable {
  • Doris数据查询规则 在数据查询业务代码中建议查询失败时进行重试,再次下发查询。 in中常量枚举值超过1000后,必须修改为子查询。 禁止使用REST API(Statement Execution Action)执行大量SQL查询,该接口仅用于集群维护。 query查询条件返回结果超过5万条,则使用JDBC Catalog或者OUTFILE方式导出查询数据,否则FE上大量数据传输将占用FE资源,影响集群稳定性。 如果是交互式查询,建议使用分页方式(offset limit)导出数据,分页命令为Order by。 如果数据导出提供给第三方使用,建议使用outfile或者export方式 2个以上大于3亿的表JOIN使用Colocation Join。 亿级别大表禁止使用select *查询数据,查询时需明确要查询的字段。 使用SQL Block方式禁止select *操作。 如果是高并发点查询,建议开启行存储(Doris 2.x版本支持),并且使用PreparedStatement查询。 亿级以上表数据查询必须设置分区分桶条件。 禁止对分区表执行全分区数据扫描操作。
  • Doris数据查询建议 一次insert into select数据超过1亿条后,建议拆分为多个insert into select语句执行,分成多个批次来执行。 不要使用OR作为JOIN条件。 不建议频繁的数据delete修改,将要删除的数据攒批,偶尔进行批量删除,且需要带上条件,提升系统稳定性和删除效率。 大量数据排序(5亿以上)后返回部分数据,建议先减少数据范围再执行排序,否则大量排序会影响性能。例如: 将from table order by datatime desc limit 10优化为from table where datatime='2023-10-20' order by datatime desc limit 10。 查询任务性能调优参数parallel_fragment_exec_instance_num使用注意事项: 此参数是session级别设置,表示可并发执行的fragment数量,对CPU消耗较大,因此一般情况下不需要设置此参数。如果需要设置此参数来加速查询性能,必须遵循以下规则: 切勿设置该参数为全局生效,禁止使用set global方式进行设置。 设置参数值建议为偶数2或4(最大值不要超过单节点CPU核数的一半)。 设置此参数值时需要观察CPU使用率,CPU使用率小于50%时方可考虑设置。 如果查询SQL是insert into select大数据量的方式,不建议设置此参数。
  • HQL编写之隐式类型转换 查询语句使用字段的值做过滤时,不建议通过Hive自身的隐式类型转换来编写HQL。因为隐式类型转换不利于代码的阅读和移植。 建议示例: select * from default.tbl_src where id = 10001;select * from default.tbl_src where name = 'TestName'; 不建议示例: select * from default.tbl_src where id = '10001';select * from default.tbl_src where name = TestName; 表tbl_src的id字段为Int类型,name字段为String类型。
  • 避免写入单条记录超大的数据 单条记录超大的数据在影响处理效率的同时还可能写入失败,此时需要在初始化Kafka生产者实例时根据情况调整“max.request.size ”值,在初始化消费者实例时调整“max.partition.fetch.bytes”值。 例如,参考本例,可以将max.request.size 、max.partition.fetch.bytes配置项设置为“5252880”: // 协议类型:当前支持配置为SASL_PLAINTEXT或者PLAINTEXT props.put(securityProtocol, kafkaProc.getValues(securityProtocol, "SASL_PLAINTEXT")); // 服务名 props.put(saslKerberosServiceName, "kafka"); props.put("max.request.size", "5252880"); // 安全协议类型 props.put(securityProtocol, kafkaProc.getValues(securityProtocol, "SASL_PLAINTEXT")); // 服务名 props.put(saslKerberosServiceName, "kafka"); props.put("max.partition.fetch.bytes","5252880");
  • Scan时指定StartKey和EndKey 一个有确切范围的Scan,在性能上会带来较大的好处。 代码示例: Scan scan = new Scan();scan.addColumn(Bytes.toBytes("familyname"),Bytes.toBytes("columnname"));scan.setStartRow( Bytes.toBytes("rowA")); // 假设起始Key为rowAscan.setStopRow( Bytes.toBytes("rowB")); // 假设EndKey为rowBfor(Result result : demoTable.getScanner(scan)) {// process Result instance}
  • 不要调用Admin的closeRegion方法关闭一个Region Admin中,提供了关闭一个Region的接口: public void closeRegion(final String regionname, final String serverName) 通过该方法关闭一个Region,HBase Client端会直接发RPC请求到Region所在的RegionServer上,整个流程对Master而言,是不感知的。也就是说,尽管RegionServer关闭了这个Region,但是,在Master侧,还以为该Region是在该RegionServer上面打开的。假如,在执行Balance的时候,Master计算出恰好要转移这个Region,那么,这个Region将无法被关闭,本次转移操作将无法完成(关于这个问题,在当前的HBase版本中的处理的确还欠缺妥当)。 因此,暂时不建议使用该方法关闭一个Region。
  • 创建一张表或Scan时设定blockcache为true HBase客户端建表和scan时,设置blockcache=true。需要根据具体的应用需求来设定它的值,这取决于有些数据是否会被反复的查询到,如果存在较多的重复记录,将这个值设置为true可以提升效率,否则,建议关闭。 建议按默认配置,默认就是true,只要不强制设置成false就可以,例如: HColumnDescriptor fieldADesc = new HColumnDescriptor("value".getBytes());fieldADesc.setBlockCacheEnabled(false);
  • 不要关闭WAL WAL是Write-Ahead-Log的简称,是指数据在入库之前,首先会写入到日志文件中,借此来确保数据的安全性。 WAL功能默认是开启的,但是,在Put类中提供了关闭WAL功能的接口: public void setWriteToWAL(boolean write) 因此,不建议调用该方法将WAL关闭(即将writeToWAL设置为False),因为可能会造成最近1S(该值由RegionServer端的配置参数“hbase.regionserver.optionallogflushinterval”决定,默认为1S)内的数据丢失。但如果在实际应用中,对写入的速率要求很高,并且可以容忍丢失最近1S内的数据的话,可以将该功能关闭。
  • 业务表设计建议 预分Region,使Region分布均匀,提高并发 避免过多的热点Region。根据应用场景,可考虑将时间因素引入Rowkey。 同时访问的数据尽量连续存储。同时读取的数据相邻存储;同时读取的数据存放在同一行;同时读取的数据存放在同一cell。 查询频繁属性放在Rowkey前面部分。Rowkey的设计在排序上必须与主要的查询条件契合。 离散度较好的属性作为RowKey组成部分。分析数据离散度特点以及查询场景,综合各种场景进行设计。 存储冗余信息,提高检索性能。使用二级索引,适应更多查询场景。 利用过期时间、版本个数设置等操作,让表能自动清除过期数据。 在HBase中,一直在繁忙写数据的Region被称为热点Region。