更新时间:2025-12-12 GMT+08:00
分享

使用脚本完成随机内容抽样比对

  1. 在华为云购买一台与源端、目的端都相通的ECS(建议购买CentOS操作系统的ECS)。

    图1 购买ECS

    要使该ECS和源端目的端数据库都通,需要在源端和目的端配置安全组。

    • 源端设置服务器防火墙

    • 目的端设置安全组

    • 结果

  2. 在第一步购买的ECS上安装sqlcmd

    安装参考:在 Linux 上安装 sqlcmd 和 bcp SQL Server 命令行工具

    安装步骤如下:
    1. 下载Microsoft Red Hat存储库配置文件

      curl https://packages.microsoft.com/config/rhel/8prod.repo | sudo tee /etc/yum.repos.d/mssql-release.repo

    1. 如果安装了早期版本的mssql-tools,请删除所有旧的unixODBC包

      sudo yum remove mssql-tools unixODBC-utf16 unixODBC-utf16-devel

    1. 运行以下命令,以使用unixODBC开发人员包安装mssql-tools18

      sudo yum install -y mssql-tools18 unixODBC-devel

      若要将mssql-tools更新至最新版本,请运行以下命令:

      sudo yum check-update

      sudo yum update mssql-tools18

    2. 向bash shell中的PATH环境变量添加/opt/mssql-tools18/bin/

      若要使sqlcmd和bcp能从登录会话的 bash shell 进行访问,请使用下列命令修改~/.bash_profile 文件中的 PATH

      echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bash_profile

      source ~/.bash_profile

  3. 将校验脚本、源端/目的端的配置信息文件、校验表配置文件导入ECS。

    ECS check脚本如下:

    #!/bin/bash
    
    # 日志函数
    log() {
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
    }
    
    # 错误处理函数
    error_exit() {
        log "错误: $1"
        exit 1
    }
    
    # 检查参数
    if [ "$#" -ne 2 ]; then
        error_exit "用法: $0 <配置文件路径> <表信息文件路径>"
    fi
    
    config_file=$1
    table_info_file=$2
    
    # 检查文件是否存在
    [ -f "$config_file" ] || error_exit "配置文件 $config_file 不存在"
    [ -f "$table_info_file" ] || error_exit "表信息文件 $table_info_file 不存在"
    
    # 读取第一个SQL Server连接信息
    server1=$(awk -F'=' '/^server1/ {print $2}' "$config_file" | tr -d ' ')
    user1=$(awk -F'=' '/^user1/ {print $2}' "$config_file" | tr -d ' ')
    password1=$(awk -F'=' '/^password1/ {print $2}' "$config_file" | tr -d ' ')
    database1=$(awk -F'=' '/^database1/ {print $2}' "$config_file" | tr -d ' ')
    
    # 读取第二个SQL Server连接信息
    server2=$(awk -F'=' '/^server2/ {print $2}' "$config_file" | tr -d ' ')
    user2=$(awk -F'=' '/^user2/ {print $2}' "$config_file" | tr -d ' ')
    password2=$(awk -F'=' '/^password2/ {print $2}' "$config_file" | tr -d ' ')
    database2=$(awk -F'=' '/^database2/ {print $2}' "$config_file" | tr -d ' ')
    
    # 检查连接信息是否完整
    if [ -z "$server1" ] || [ -z "$user1" ] || [ -z "$password1" ] || [ -z "$database1" ] ||
       [ -z "$server2" ] || [ -z "$user2" ] || [ -z "$password2" ] || [ -z "$database2" ]; then
        error_exit "配置文件缺少必要的连接信息"
    fi
    
    # 检查sqlcmd是否可用
    command -v sqlcmd >/dev/null 2>&1 || error_exit "sqlcmd命令未找到,请确保SQL Server命令行工具已安装"
    
    # 处理表信息文件
    total_tables=0
    success_tables=0
    failed_tables=0
    
    for line in `cat  $table_info_file`
    do
        # 去除空格
        table1=$(echo $line | awk -F',' '{print $1}' | tr -d ' ')
        table2=$(echo $line | awk -F',' '{print $2}' | tr -d ' ')
        pk_column=$(echo $line | awk -F',' '{print $3}' | tr -d ' ')
        gt_value=$(echo $line | awk -F',' '{print $4}' | tr -d ' ')
        lt_value=$(echo $line | awk -F',' '{print $5}' | tr -d ' ')
    
        ((total_tables++))
        log "开始比较表 #$total_tables: $table1 (服务器1) 和 $table2 (服务器2)"
    
        # 构建WHERE子句
        where_clause=""
        if [ -n "$pk_column" ]; then
            conditions=()
    
            if [ -n "$gt_value" ]; then
                conditions+=("$pk_column > $gt_value")
            fi
    
            if [ -n "$lt_value" ]; then
                conditions+=("$pk_column < $lt_value")
            fi
    
            if [ ${#conditions[@]} -gt 0 ]; then
                where_clause="WHERE $(printf '%s AND ' "${conditions[@]}" | sed 's/ AND $//')"
            fi
        fi
    
        # 获取表1的checksum
        sql1="SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) AS checksum FROM $table1 $where_clause"
        checksum1=$(sqlcmd -S "$server1" -U "$user1" -P "$password1" -d "$database1" -h -1 -Q "SET NOCOUNT ON; $sql1" 2>/dev/null | tr -d ' ' | tr -d '\r\n')
    
        if [ $? -ne 0 ]; then
            log "警告: 无法获取表 $table1 的checksum,跳过此表"
            ((failed_tables++))
            echo "----------------------------------------"
            continue
        fi
    
        # 获取表2的checksum
        sql2="SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) AS checksum FROM $table2 $where_clause"
    
        checksum2=$(sqlcmd -S "$server2" -U "$user2" -P "$password2" -d "$database2" -h -1 -Q "SET NOCOUNT ON; $sql2" 2>/dev/null | tr -d ' ' | tr -d '\r\n')
    
        if [ $? -ne 0 ]; then
            log "警告: 无法获取表 $table2 的checksum,跳过此表"
            ((failed_tables++))
            echo "----------------------------------------"
            continue
        fi
    
    
        # 比较checksum
        if [ "$checksum1" == "$checksum2" ]; then
            log "结果: 表内容一致 (Checksum: $checksum1)"
            ((success_tables++))
        else
            log "结果: 表内容不一致"
            log "表 $table1 (服务器1) Checksum: $checksum1"
            log "表 $table2 (服务器2) Checksum: $checksum2"
            ((failed_tables++))
    
        fi
    
        echo "----------------------------------------"
    done
    
    log "比较完成"
    log "总计表数: $total_tables"
    log "一致表数: $success_tables"
    log "不一致表数: $failed_tables"
    
    if [ "$failed_tables" -gt 0 ]; then
        exit 1
    else
        exit 0
    fi
    
    • 源/目标信息配置文件

      vi config.cfg

      server1=testdbvm.database.windows.net

      user1=azuser

      password1=XXXXX

      database1=smsa_mig

      server2= 123.60.216.120

      user2=rdsuser

      password2=XXXXXXX

      database2= smsa_mig

      server user password与database用户需要按照实际需要修改。

    • 同步对比表配置文件

      (源表名,目标表名,主键,> 范围,<范围,逗号分隔)

      vim table_info.txt

      如第一行校验dbo.check1全表,不指定范围

      如第二行校验dbo.check2,根据id>11 and id < 13的范围校验

      dbo.check1,dbo.check1

      dbo.check2,dbo.check2,id,11,13

  4. 执行校验文件脚本。

    sh chech.sh config.cfg table_info.txt

相关文档