clickhouse数据库表和doris数据库表迁移starrocks数据库时建表注意事项总结

目录

    • 零、前言
    • 一、clickhouse数据库表在starrocks数据库建表时问题总结
      • [1.1 数据类型类问题:](#1.1 数据类型类问题:)
      • [1.2 数据导出阶段:](#1.2 数据导出阶段:)
    • [二、doris 数据库表在starrocks数据库建表时问题总结](#二、doris 数据库表在starrocks数据库建表时问题总结)
      • [2.1 properties不支持的属性(直接删除):](#2.1 properties不支持的属性(直接删除):)
      • [2.2 properties需修改属性](#2.2 properties需修改属性)
      • [2.3 properties:doris建表语句分区明细,starrocks数据不需要明确设定,会自动更新](#2.3 properties:doris建表语句分区明细,starrocks数据不需要明确设定,会自动更新)
      • [2.4 分桶设置问题](#2.4 分桶设置问题)
      • [2.5 索引设置问题](#2.5 索引设置问题)
      • [2.6 python程序针对上述问题解决程序](#2.6 python程序针对上述问题解决程序)
    • 三、小结

零、前言

这可能是个技术选型的问题,前期各自为营,所以整个企业内部,数据库类型五花八门,相互之间数据也很难对齐引用。随着业务等等大势所趋,需要整合全公司资源,因此由来了这个数据资源迁移。针对迁移过程中的建表方面,作一总结,以备后续问题原因排查和进一步整改,让过程有迹可循。

一、clickhouse数据库表在starrocks数据库建表时问题总结

1.1 数据类型类问题:

  1. 字符类型varchar需要指定位数,默认位数为1,会导致 导入数据为空;
  2. 其它的类型映射遇到的映射关系,遇到的类型处理映射关系整理如下,其中key为clickhouse中的数据类型,value为对应的starrocks数据库类型:

{

'Date': 'DATE',

'Nullable(Date)': 'DATE NULL',

'DateTime': 'DATETIME',

'Nullable(DateTime)': 'DATETIME NULL',

'Float64': 'FLOAT',

'Float32': 'FLOAT',

'Nullable(Float32)': 'FLOAT NULL',

'Nullable(Float64)': 'FLOAT NULL',

'Int32': 'INT', 'UInt32': 'INT',

'UInt16': 'INT',

'Int64': 'INT',

'Nullable(Int32)': 'INT NULL',

'Nullable(Int8)': 'INT NULL',

'Nullable(UInt32)': 'INT NULL',

'Nullable(Int64)': 'INT NULL',

'String': 'varchar(65535)',

'Nullable(String)': 'varchar(65535) NULL'

}

1.2 数据导出阶段:

  1. 默认通过【select * from table_name limit num offset offnum 】的形式进行大文件分拆,不指定排序会导致数据导出重复。这应该是大部分数据库的通病,需要注意先对数据按指定字段排序,再移动分块,就可以避免,当然就需要对该表多少有一些熟悉度,诸如主键等进行了解;
  2. clickhouse数据库通过【clickhouse-client】导出parquet文件,对于 日期时间类型 ,不明确通过 cast(字段名称 as datetime) 进行设定,会将日期时间转换为时间戳;

二、doris 数据库表在starrocks数据库建表时问题总结

doris数据库表DDL在starrocks中存在最主要的问题就是 properties属性 修改适配,字段类型目前所用类型全部可以在starrocks数据库中适配使用,所以无需更改。问题总结集中在properties方面。

2.1 properties不支持的属性(直接删除):

复制代码
	"is_being_synced" = "false",
	"disable_auto_compaction" = "false",
	"enable_single_replica_compaction" = "false"
	"light_schema_change" = "true" 
	"dynamic_partition.create_history_partition" = "false",
	"dynamic_partition.storage_medium" = "HDD",
	"dynamic_partition.storage_policy" = "",
	"dynamic_partition.hot_partition_num" = "0",
	"dynamic_partition.reserved_history_periods" = "NULL",
	"enable_mow_light_delete" = "false"
	"light_schema_change" = "true"

2.2 properties需修改属性

复制代码
	"replication_allocation" = "tag.location.default: 3"     				改为 "replication_num" = "3",
	"dynamic_partition.replication_allocation" = "tag.location.default: 3"  改为 "dynamic_partition.replication_num" = "3" 
	"dynamic_partition.history_partition_num" = "1200" starrocks数据库默认动态分区上限500,目前直接删除该属性

2.3 properties:doris建表语句分区明细,starrocks数据不需要明确设定,会自动更新

复制代码
	a.PARTITION BY RANGE(`xxx`) 之后的明细分区,全部删除,不需指定,但括号需要保留。如:PARTITION BY RANGE(`xxx`)()
	b."dynamic_partition.start" = "-2147483648"  删除,不需指定

2.4 分桶设置问题

复制代码
	DISTRIBUTED BY HASH(`vin`) BUCKETS AUTO ,starrocks不支持auto属性,直接设定具体数字,eg:10

2.5 索引设置问题

复制代码
	索引类型:INDEX idx_vin (vin) USING INVERTED COMMENT '',starrocks不支持 INVERTED ,将索引类型修改为: USING BITMAP 即可。

2.6 python程序针对上述问题解决程序

python 复制代码
# 删除分区明细
# 匹配分区定义部分,从(PARTITION开始到三个连续的右括号结束
# re.IGNORECASE:使正则表达式匹配时忽略大小写。 
# re.DOTALL:使 . 匹配任意字符,包括换行符。
pattern = r"\(PARTITION.*\){3}"
# step_one_sql = re.sub(pattern, "", sql, flags=re.IGNORECASE | re.DOTALL) # 这个会将分区明细全部剔除,且没有保留RANGE之后的明细需要的括号
step_one_sql = re.sub(pattern, "()", sql, flags=re.IGNORECASE | re.DOTALL) # 对上述sql的修正

# 正则表达式匹配并替换 BUCKETS AUTO 为 BUCKETS 10
step_one_sql = re.sub(r" BUCKETS AUTO", r" BUCKETS 10", step_one_sql) 

# 正则表达式匹配索引类型:并替换 
step_one_sql = re.sub(r" USING INVERTED ", r" USING BITMAP ", step_one_sql) 

# 正则表达式匹配 PROPERTIES 部分
pattern = r"(PROPERTIES\s*\([\s\S]*?\);)"
match = re.search(pattern, step_one_sql)    
if match:
	# 提取 PROPERTIES 部分
	properties_content = match.group(1)

	# 删除不支持的属性
	properties_content = re.sub(r'"is_being_synced"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"disable_auto_compaction"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"enable_single_replica_compaction"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"light_schema_change"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.create_history_partition"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.storage_medium"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.storage_policy"\s*=\s*""\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.hot_partition_num"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.reserved_history_periods"\s*=\s*"\w+"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.start"\s*=\s*"[\w\d-]*"\s*,?', '', properties_content)
	properties_content = re.sub(r'"dynamic_partition\.history_partition_num"\s*=\s*"[\w\d-]*"\s*,?', '', properties_content)
	properties_content = re.sub(r'"enable_mow_light_delete"\s*=\s*"\w+"\s*,?', '', properties_content)
	

	# 修改属性
	properties_content = re.sub(
		r'"replication_allocation"\s*=\s*"tag\.location\.default:\s*\d+"',
		'"replication_num" = "3"',
		properties_content
	)
	# properties_content = re.sub(
	#     r'"light_schema_change"\s*=\s*"\w+"',
	#     '"enable_light_schema_change" = "true"',
	#     properties_content
	# )
	properties_content = re.sub(
		r'"dynamic_partition.replication_allocation"\s*=\s*"tag\.location\.default:\s*\d+"',
		'"dynamic_partition.replication_num" = "3"',
		properties_content
	)
	# properties_content = re.sub(
	#     r'"dynamic_partition.history_partition_num" = "-1"',
	#     '"dynamic_partition.history_partition_num" = "30"',
	#     properties_content
	# )

	# 清理多余的逗号和空白行
	properties_content = re.sub(r",\s*,", ",", properties_content)  # 清理多余的逗号
	properties_content = re.sub(r"\n\s*\n", "\n", properties_content)  # 清理空白行


	"""最后一个属性后 会有逗号,进行替换"""
	# 正则表达式:匹配 PROPERTIES 块中的最后一个逗号
	pattern = r'(?s)(PROPERTIES\s*\(.*?)(,\s*\);)'  # (?s) 表示单行模式,匹配换行符
	# 使用 re.sub 进行替换
	def remove_last_comma(match):
		# 如果匹配到逗号,则删除
		return match.group(1) + match.group(2).replace(',', '')
	
	properties_content = re.sub(pattern, remove_last_comma, properties_content)
	
	# 更新回 SQL 语句
	updated_sql = step_one_sql.replace(match.group(1), properties_content)

三、小结

初步测试上述问题解决方案运行可行,后续遇到新问题再进行补充更新。现有的豆包之类的工具,着实提高了问题解决的效率,从而让我们有了更多的思考时间。拥抱新工具,喜迎新未来。

相关推荐
nbsaas-boot29 分钟前
SQL Server 窗口函数全指南(函数用法与场景)
开发语言·数据库·python·sql·sql server
Y.ppm29 分钟前
数分思维12:SQL技巧与分析方法
数据库·sql
森叶32 分钟前
Claude Code 安装向量数据库MCP服务
数据库
bestsun99933 分钟前
Time drifts can result in unexpected behavior such as time-outs.
数据库·oracle
waveee1232 小时前
学习嵌入式的第三十四天-数据结构-(2025.7.29)数据库
数据结构·数据库·学习
何传令2 小时前
SQL优化系统解析
数据库·sql·mysql
找不到、了2 小时前
Redis内存使用耗尽情况分析
数据库·redis·缓存
DarkAthena2 小时前
【GaussDB】内存资源告急:深度诊断一起“memory temporarily unavailable“故障
数据库·gaussdb
小云数据库服务专线2 小时前
GaussDB as的用法
数据库·sql·gaussdb
hzk的学习笔记3 小时前
Redis的事务和Lua之间的区别
数据库·redis·缓存