0 前言
原计划国庆节更新一篇,万万没想到居然真的有人催更,感谢小伙伴给了中年后浪熬夜的理由。出于安全和用户体验提升等方面考虑,最近在备份并优化某新城SDE数据。下面记录并总结一下本项任务。1 现状分析
1.1 数据库现状
数据类型
数据种类:基础地理空间框架、调查评价、国土空间规划、管理审批、招商管理、建设管理等类型数据
存储类型:以要素集(FeatureClass)和数据集(FeatureDataset)类型存储
数据管理权限
两个管理员:均具备SDE管理员权限,可读写数据
两类数据:两个SDE管理员均创建各自的要素集和数据集,且部分数据实时更新
1.2 主要需求
备份SDE中多个管理员用户创建的数据
每天凌晨23:23:23启动备份计划
2 技术路线
2.1 常用方法汇总
备份SDE有诸多技巧,我只说我会的。不想看文字的直接看脑图。ArcCatalog导出
优点:上手快
缺点:数据量大时非最优解
SDE命令行:使用sdeexport导出为exp格式文件
优点:快,命令简单,结果粗暴
缺点:太快,SDE命令行配置稍复杂,结果过于粗暴所以不直观
ArcPy函数批量复制
优点:较快,代码量小,结果直观
缺点:与python包融合使用方面可能会遇到未知错误(详见3.1)
FME Server中运行scheduled workspace
优点:绝对可行(但与本文ArcPy主题无关)
缺点:试用版FME Server已过期,无法测试是否绝对可行(其实schedule是FME Server中常规操作)
2.2 ArcPy路线流程图
见流程图。3 实现流程
3.1 ArcPy备份SDE
使用到的ArcPy函数
CreateFileGDB_management:创建一个GDB
CreateFeatureDataset_management:创建一个DS
CopyFeatures_management:复制一个要素集中要素到另一个要素集
ListFeatureClasses:
语法:ListFeatureClasses({wild_card},{feature_type},{feature_dataset})
说明:设置工作空间后才能使用列表函数
返回值:返回要素集列表,配置wild_card和feature_type,返回符合条件的要素集列表
da.Walk
语法:Walk (top, {topdown}, {onerror}, {followlinks}, {datatype}, {type})
说明:遍历目录树,生成目录树中文件名。函数类似于Python的os.walk()函数,但是os.walk()基于文件,不能识别地理数据要素类、表或栅格等数据库内容
返回值:返回三元组包括工作空间、目录名称和文件名称 (dirpath, dirnames, and filenames)
坑清单
坑1
坑描述:da.walk()中遍历完FC和DS后,循环不会终止,继续执行导致程序报错
脱坑:使用break跳出当前循环
坑2
坑描述:多个SDE管理员可能创建同名FC,导出到同一个GDB中报错
脱坑:根据用户名分别创建GDB
码
def SdeBak(gbdpath, gdbname_sde,gdbname_user): sde_con = 'Database Connections/SDE@Connection to ***.sde' arcpy.env.overwriteOutput = True # 设置ws arcpy.env.workspace = sde_con str_td = datetime.date.today().strftime('%Y%m%d') # 指向gdb out_gdbpath = gbdpath out_gdbname_sde = '{}{}'.format(gdbname_sde, str_td) out_gdb_sde = os.path.join(out_gdbpath, out_gdbname_sde + '.gdb') out_gdbname_user = '{}{}'.format(gdbname_user, str_td) out_gdb_user = os.path.join(out_gdbpath, out_gdbname_user + '.gdb') # 创建GDB arcpy.CreateFileGDB_management(out_gdbpath, out_gdbname_sde, 'CURRENT') arcpy.CreateFileGDB_management(out_gdbpath, out_gdbname_user, 'CURRENT') print('SDE GDB Created,GDB Path:{}'.format(out_gdb_sde)) print('CJXCUSER GDB Created,GDB Path:{}'.format(out_gdb_user)) for dirpath, dirnames, filenames in arcpy.da.Walk(sde_con, datatype="FeatureClass",type=['Polygon', 'Polyline', 'Point']): # 遍历要素集及要素集中要素类并进行拷贝 for ds in dirnames: # 非SDE用户创建数据不导出 if 'SDE' in ds: dsname = arcpy.Describe(ds).basename outdsname = os.path.join(out_gdb_sde, dsname.split('.')[1]) sr = arcpy.Describe(ds).SpatialReference print(outdsname) arcpy.CreateFeatureDataset_management(out_gdb_sde, dsname.split('.')[1], sr) fclist = arcpy.ListFeatureClasses('', '', dsname) for fc in fclist: basename = arcpy.Describe(fc).basename outname = os.path.join(outdsname, basename.split('.')[1]) str = basename.split('.')[1] print(str + " Copy Done") arcpy.CopyFeatures_management(fc, outname) elif 'CJXCUSER' in ds: dsname = arcpy.Describe(ds).basename outdsname = os.path.join(out_gdb_user, dsname.split('.')[1]) sr = arcpy.Describe(ds).SpatialReference print(outdsname) arcpy.CreateFeatureDataset_management(out_gdb_user, dsname.split('.')[1], sr) fclist = arcpy.ListFeatureClasses('', '', dsname) for fc in fclist: basename = arcpy.Describe(fc).basename outname = os.path.join(outdsname, basename.split('.')[1]) str = basename.split('.')[1] print(str + " Copy Done") arcpy.CopyFeatures_management(fc, outname) # 遍历要素类数据并进行拷贝 for fc in filenames: print(fc) if 'SDE' in fc: outname = os.path.join(out_gdb_sde, fc.split('.')[1]) elif 'CJXCUSER' in fc: outname = os.path.join(out_gdb_user, fc.split('.')[1]) str = fc.split('.')[1] arcpy.CopyFeatures_management(fc, outname) print(str + ' Copy Done') #终止循环 break print('SDE Backup Accomplished,Backup Date:{}'.format(str_td))
3.2 定时任务调度
schedule包
上篇B站链接中介绍过schedule包用法,但是对于3号坑的确始料未及。
坑3
坑描述:通过schedule定时调度arcpy.os.walk()函数时,无返回值
脱坑:不用此包,换思路
windows自带Task Scheduler
创建一个bat文件,用于执行.py文件
cd C:\Python27\ArcGIS10.2python E:\CJXCSDE_BACKUP\SdeBak.pypause
配置Task Scheduler(任务计划程序)
说明:不同操作系统界面和步骤略有不同
位置:管理工具->任务计划程序->创建任务
触发器配置:设置每天23:23:23执行
操作配置:新建一个启动程序,指向bat脚本
4 总结
备份SDE看似简单的需求和目标实现起来却是一波三折,感慨下自己知识的非系统性和碎片化,以及思维逻辑的非严密性。道阻且长,行则将至。下篇见。