Skip to content

TDSQL 常用脚本示例

监控脚本示例

监控脚本用于实时监控TDSQL数据库的性能和状态,帮助运维人员及时发现问题。以下是两个常用的监控脚本示例:

1. 性能监控脚本

功能说明:定期采集TDSQL数据库的核心性能指标,包括QPS、TPS、连接数和慢查询数,并记录到日志文件中。当连接数超过阈值时,会生成告警日志。

使用场景:适用于日常性能监控,可配置为每分钟或每小时执行一次,及时发现性能异常。

配置方法:修改脚本中的数据库连接信息、日志路径和告警阈值。

注意事项:确保监控用户只具有只读权限,避免安全风险。

bash
#!/bin/bash
# TDSQL 性能监控脚本
# 功能:采集QPS、TPS、连接数和慢查询数等性能指标
# 适用场景:日常性能监控

# 配置参数
HOST="localhost"      # 数据库主机地址
PORT="3306"           # 数据库端口
USER="monitor"        # 监控用户名,建议使用只读用户
PASSWORD="password"    # 监控用户密码
LOG_FILE="/var/log/tdsql_performance.log"  # 日志文件路径
ALERT_CONNECTIONS=1000  # 连接数告警阈值

# 构建MySQL连接命令
MYSQL="mysql -h$HOST -P$PORT -u$USER -p$PASSWORD -N -e"

# 获取当前时间戳
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")

# 采集性能指标
# 获取查询总数(用于计算QPS)
QPS=$($MYSQL "SHOW GLOBAL STATUS LIKE 'Queries'" | awk '{print $2}')
# 获取提交的事务数
TPS=$($MYSQL "SHOW GLOBAL STATUS LIKE 'Com_commit'" | awk '{print $2}')
# 获取回滚的事务数
ROLLBACKS=$($MYSQL "SHOW GLOBAL STATUS LIKE 'Com_rollback'" | awk '{print $2}')
# 获取当前连接数
CONNECTIONS=$($MYSQL "SHOW GLOBAL STATUS LIKE 'Threads_connected'" | awk '{print $2}')
# 获取慢查询总数
SLOW_QUERIES=$($MYSQL "SHOW GLOBAL STATUS LIKE 'Slow_queries'" | awk '{print $2}')

# 计算总TPS(提交+回滚)
TOTAL_TPS=$((TPS + ROLLBACKS))

# 记录性能指标到日志文件
echo "$TIMESTAMP QPS:$QPS TPS:$TOTAL_TPS CONNECTIONS:$CONNECTIONS SLOW_QUERIES:$SLOW_QUERIES" >> $LOG_FILE

# 输出性能指标到控制台(便于手动执行时查看)
echo "性能指标($TIMESTAMP):"
echo "QPS: $QPS"
echo "TPS: $TOTAL_TPS"
echo "连接数: $CONNECTIONS"
echo "慢查询数: $SLOW_QUERIES"

# 连接数告警检查
if [ $CONNECTIONS -gt $ALERT_CONNECTIONS ]; then
    echo "警告:连接数超过阈值($ALERT_CONNECTIONS),当前值为 $CONNECTIONS" >> $LOG_FILE
    # 此处可以添加告警通知,如发送邮件或短信
    # echo "TDSQL连接数告警:当前连接数 $CONNECTIONS 超过阈值 $ALERT_CONNECTIONS" | mail -s "TDSQL性能告警" admin@example.com
fi

2. 状态监控脚本

功能说明:检查TDSQL实例的运行状态,包括实例角色(主库/从库)、主从复制状态和磁盘空间使用情况。

使用场景:适用于实例状态巡检,可配置为每小时执行一次,确保实例正常运行。

配置方法:修改脚本中的数据库连接信息。

注意事项:对于分布式实例,需要分别检查每个分片的状态。

python
#!/usr/bin/env python3
# TDSQL 状态监控脚本
# 功能:检查实例角色、主从状态和磁盘空间
# 适用场景:实例状态巡检

import pymysql
import time
import sys

# 配置参数
config = {
    'host': 'localhost',      # 数据库主机地址
    'port': 3306,             # 数据库端口
    'user': 'monitor',        # 监控用户名
    'password': 'password',    # 监控用户密码
    'database': 'information_schema'  # 连接的数据库
}

# 尝试连接数据库
print("正在连接数据库...")
try:
    conn = pymysql.connect(**config)
    cursor = conn.cursor()
    print("数据库连接成功")
except Exception as e:
    print(f"数据库连接失败: {e}")
    sys.exit(1)

# 检查实例角色(主库/从库)
def check_instance_status():
    """检查实例是主库还是从库"""
    try:
        cursor.execute("SELECT @@global.read_only")
        read_only = cursor.fetchone()[0]
        if read_only == 0:
            return "主库"
        else:
            return "从库"
    except Exception as e:
        return f"检查失败: {e}"

# 检查主从复制状态
def check_replication_status():
    """检查主从复制状态,包括IO线程和SQL线程状态,以及复制延迟"""
    try:
        cursor.execute("SHOW SLAVE STATUS")
        slave_status = cursor.fetchone()
        if not slave_status:
            return "未配置主从"
        
        # 获取复制状态信息
        slave_io_running = slave_status[10]   # IO线程状态
        slave_sql_running = slave_status[11]  # SQL线程状态
        seconds_behind_master = slave_status[32]  # 复制延迟(秒)
        
        # 判断复制状态
        if slave_io_running == 'Yes' and slave_sql_running == 'Yes':
            if seconds_behind_master is None:
                return f"主从正常,延迟: 0秒"
            else:
                return f"主从正常,延迟: {seconds_behind_master}秒"
        else:
            return f"主从异常: IO={slave_io_running}, SQL={slave_sql_running}"
    except Exception as e:
        return f"检查失败: {e}"

# 检查磁盘空间
def check_disk_space():
    """检查数据库服务器的磁盘空间使用情况"""
    try:
        import os
        # 获取根目录磁盘状态
        statvfs = os.statvfs('/')
        # 计算可用空间(GB)
        free_space = statvfs.f_frsize * statvfs.f_bavail / (1024 ** 3)
        # 计算总空间(GB)
        total_space = statvfs.f_frsize * statvfs.f_blocks / (1024 ** 3)
        # 计算使用率(%)
        used_percent = (1 - statvfs.f_bavail / statvfs.f_blocks) * 100
        
        return f"磁盘空间: 总容量={total_space:.2f}GB, 可用={free_space:.2f}GB, 使用率={used_percent:.1f}%"
    except Exception as e:
        return f"检查失败: {e}"

# 执行检查并输出结果
print("\n=== TDSQL 状态检查结果 ===")
print(f"检查时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"实例角色: {check_instance_status()}")
print(f"主从状态: {check_replication_status()}")
print(f"磁盘空间: {check_disk_space()}")
print("=========================")

# 关闭数据库连接
cursor.close()
conn.close()
print("\n数据库连接已关闭")

备份恢复脚本示例

备份是保障数据安全的重要手段,以下是两个常用的备份脚本示例:

1. 全量备份脚本

功能说明:对TDSQL数据库进行全量备份,包括所有数据库、存储过程、触发器和事件,并压缩存储。备份完成后会验证备份文件的完整性,并清理过期备份。

使用场景:适用于每日全量备份,建议在业务低峰期执行。

配置方法:修改脚本中的数据库连接信息、备份路径和备份保留天数。

注意事项:确保备份目录有足够的存储空间,建议使用独立的备份存储设备。

bash
#!/bin/bash
# TDSQL 全量备份脚本
# 功能:执行全量备份并验证备份文件完整性
# 适用场景:每日全量备份

# 配置参数
HOST="localhost"              # 数据库主机地址
PORT="3306"                   # 数据库端口
USER="backup"                 # 备份用户名,需具有备份权限
PASSWORD="password"           # 备份用户密码
BACKUP_DIR="/backup/tdsql/full"  # 备份文件存储路径
LOG_FILE="/var/log/tdsql_backup.log"  # 备份日志路径
RETENTION_DAYS=7              # 备份保留天数,超过此天数的备份将被清理

# 创建备份目录(如果不存在)
mkdir -p $BACKUP_DIR

# 生成备份文件名,格式:tdsql_full_年月日_时分秒.sql.gz
BACKUP_FILE="${BACKUP_DIR}/tdsql_full_$(date +"%Y%m%d_%H%M%S").sql.gz"

# 记录备份开始日志
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始执行TDSQL全量备份..." >> $LOG_FILE

# 执行全量备份
# --all-databases:备份所有数据库
# --single-transaction:使用事务保证备份一致性
# --routines:备份存储过程和函数
# --triggers:备份触发器
# --events:备份事件
mysqldump -h$HOST -P$PORT -u$USER -p$PASSWORD --all-databases --single-transaction --routines --triggers --events | gzip > $BACKUP_FILE

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 全量备份成功,备份文件:$BACKUP_FILE" >> $LOG_FILE
    
    # 验证备份文件完整性
    echo "$(date +"%Y-%m-%d %H:%M:%S") 开始验证备份文件完整性..." >> $LOG_FILE
    gunzip -t $BACKUP_FILE
    if [ $? -eq 0 ]; then
        echo "$(date +"%Y-%m-%d %H:%M:%S") 备份文件验证成功" >> $LOG_FILE
    else
        echo "$(date +"%Y-%m-%d %H:%M:%S") 备份文件验证失败,已删除损坏的备份文件" >> $LOG_FILE
        rm -f $BACKUP_FILE
    fi
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") 全量备份失败" >> $LOG_FILE
    exit 1
fi

# 清理过期备份
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始清理 $RETENTION_DAYS 天前的过期备份..." >> $LOG_FILE
find $BACKUP_DIR -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
if [ $? -eq 0 ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 过期备份清理完成" >> $LOG_FILE
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") 过期备份清理失败" >> $LOG_FILE
fi

# 记录备份结束日志
echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL全量备份任务完成" >> $LOG_FILE
echo "-----------------------------------------------------------------" >> $LOG_FILE

2. 增量备份脚本

功能说明:基于二进制日志的增量备份,只备份自上次备份以来的变更数据。

使用场景:适用于高频率备份,可配置为每小时执行一次,减少备份窗口和存储空间占用。

配置方法:修改脚本中的数据库连接信息、备份路径和备份保留天数。

注意事项:需要确保数据库已启用二进制日志,且主从复制正常。

bash
#!/bin/bash
# TDSQL 增量备份脚本(基于二进制日志)
# 功能:备份自上次备份以来的二进制日志
# 适用场景:高频率增量备份

# 配置参数
HOST="localhost"                  # 数据库主机地址
PORT="3306"                       # 数据库端口
USER="backup"                     # 备份用户名
PASSWORD="password"               # 备份用户密码
BACKUP_DIR="/backup/tdsql/incremental"  # 增量备份存储路径
LOG_FILE="/var/log/tdsql_incremental_backup.log"  # 备份日志路径
RETENTION_DAYS=7                  # 备份保留天数

# 构建MySQL连接命令
MYSQL="mysql -h$HOST -P$PORT -u$USER -p$PASSWORD -N -e"

# 创建备份目录(如果不存在)
mkdir -p $BACKUP_DIR

# 记录备份开始日志
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始执行TDSQL增量备份..." >> $LOG_FILE

# 获取当前正在使用的二进制日志文件
CURRENT_LOG=$($MYSQL "SHOW MASTER STATUS" | awk '{print $1}' | tail -1)
if [ -z "$CURRENT_LOG" ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 无法获取当前二进制日志文件,可能未启用二进制日志" >> $LOG_FILE
    exit 1
fi

# 生成备份文件名
BACKUP_FILE="${BACKUP_DIR}/tdsql_incr_$(date +"%Y%m%d_%H%M%S").binlog.gz"

# 备份二进制日志
# --read-from-remote-server:从远程服务器读取二进制日志
# --raw:以原始格式保存二进制日志文件
echo "$(date +"%Y-%m-%d %H:%M:%S") 正在备份二进制日志文件:$CURRENT_LOG" >> $LOG_FILE
mysqlbinlog -h$HOST -P$PORT -u$USER -p$PASSWORD --read-from-remote-server --raw $CURRENT_LOG > "${BACKUP_FILE%.gz}"

# 压缩备份文件
gzip "${BACKUP_FILE%.gz}"

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 二进制日志备份成功,备份文件:$BACKUP_FILE" >> $LOG_FILE
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") 二进制日志备份失败" >> $LOG_FILE
    exit 1
fi

# 清理过期备份
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始清理 $RETENTION_DAYS 天前的过期增量备份..." >> $LOG_FILE
find $BACKUP_DIR -name "*.binlog.gz" -type f -mtime +$RETENTION_DAYS -delete
if [ $? -eq 0 ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 过期增量备份清理完成" >> $LOG_FILE
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") 过期增量备份清理失败" >> $LOG_FILE
fi

# 记录备份结束日志
echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL增量备份任务完成" >> $LOG_FILE
echo "-----------------------------------------------------------------" >> $LOG_FILE

日常维护脚本示例

日常维护脚本用于自动化执行TDSQL数据库的日常维护任务,减少人工操作。以下是两个常用的维护脚本示例:

1. 表优化脚本

功能说明:检查并优化存在大量碎片的表,减少磁盘空间占用,提高查询性能。

使用场景:适用于定期表优化,建议每月执行一次。

配置方法:修改脚本中的数据库连接信息和日志路径。

注意事项:表优化会锁表,建议在业务低峰期执行。

bash
#!/bin/bash
# TDSQL 表优化脚本
# 功能:优化存在大量碎片的表
# 适用场景:定期表优化

# 配置参数
HOST="localhost"              # 数据库主机地址
PORT="3306"                   # 数据库端口
USER="admin"                  # 维护用户名,需具有管理员权限
PASSWORD="password"           # 维护用户密码
LOG_FILE="/var/log/tdsql_optimize.log"  # 优化日志路径
MAX_TABLES=10                 # 一次最多优化的表数量
FRAGMENT_THRESHOLD=10*1024*1024  # 碎片大小阈值,超过此大小的表将被优化(10MB)

# 构建MySQL连接命令
MYSQL="mysql -h$HOST -P$PORT -u$USER -p$PASSWORD -N -e"

# 记录优化开始日志
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始执行TDSQL表优化任务..." >> $LOG_FILE

# 查询需要优化的表
# 条件:数据碎片大于10MB,排除系统数据库
TABLES_SQL="SELECT CONCAT(table_schema, '.', table_name) \
           FROM information_schema.tables \
           WHERE table_schema NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys') \
           AND data_free > $FRAGMENT_THRESHOLD \
           ORDER BY data_free DESC \
           LIMIT $MAX_TABLES"

tables=$($MYSQL "$TABLES_SQL")

# 检查是否有需要优化的表
if [ -z "$tables" ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 没有需要优化的表" >> $LOG_FILE
    exit 0
fi

# 输出需要优化的表列表
echo "$(date +"%Y-%m-%d %H:%M:%S") 发现需要优化的表:" >> $LOG_FILE
echo "$tables" >> $LOG_FILE

# 逐个优化表
for table in $tables; do
    echo "$(date +"%Y-%m-%d %H:%M:%S") 正在优化表:$table" >> $LOG_FILE
    
    # 执行表优化
    $MYSQL "OPTIMIZE TABLE $table"
    if [ $? -eq 0 ]; then
        echo "$(date +"%Y-%m-%d %H:%M:%S") 表 $table 优化成功" >> $LOG_FILE
    else
        echo "$(date +"%Y-%m-%d %H:%M:%S") 表 $table 优化失败" >> $LOG_FILE
    fi
done

# 记录优化结束日志
echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL表优化任务完成" >> $LOG_FILE
echo "-----------------------------------------------------------------" >> $LOG_FILE

2. 统计信息更新脚本

功能说明:更新表的统计信息,帮助优化器生成更准确的执行计划。

使用场景:适用于定期更新统计信息,建议每周执行一次。

配置方法:修改脚本中的数据库连接信息和日志路径。

注意事项:统计信息更新会锁表,建议在业务低峰期执行。

bash
#!/bin/bash
# TDSQL 统计信息更新脚本
# 功能:更新表的统计信息
# 适用场景:定期统计信息更新

# 配置参数
HOST="localhost"              # 数据库主机地址
PORT="3306"                   # 数据库端口
USER="admin"                  # 维护用户名
PASSWORD="password"           # 维护用户密码
LOG_FILE="/var/log/tdsql_analyze.log"  # 日志路径
MAX_TABLES=20                 # 一次最多更新的表数量

# 构建MySQL连接命令
MYSQL="mysql -h$HOST -P$PORT -u$USER -p$PASSWORD -N -e"

# 记录更新开始日志
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始执行TDSQL统计信息更新任务..." >> $LOG_FILE

# 查询需要更新统计信息的表
# 按最后更新时间排序,先更新长时间未更新的表
TABLES_SQL="SELECT CONCAT(table_schema, '.', table_name) \
           FROM information_schema.tables \
           WHERE table_schema NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys') \
           ORDER BY update_time ASC \
           LIMIT $MAX_TABLES"

tables=$($MYSQL "$TABLES_SQL")

# 检查是否有需要更新的表
if [ -z "$tables" ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 没有需要更新统计信息的表" >> $LOG_FILE
    exit 0
fi

# 输出需要更新的表列表
echo "$(date +"%Y-%m-%d %H:%M:%S") 发现需要更新统计信息的表:" >> $LOG_FILE
echo "$tables" >> $LOG_FILE

# 逐个更新表的统计信息
for table in $tables; do
    echo "$(date +"%Y-%m-%d %H:%M:%S") 正在更新表 $table 的统计信息" >> $LOG_FILE
    
    # 执行统计信息更新
    $MYSQL "ANALYZE TABLE $table"
    if [ $? -eq 0 ]; then
        echo "$(date +"%Y-%m-%d %H:%M:%S") 表 $table 统计信息更新成功" >> $LOG_FILE
    else
        echo "$(date +"%Y-%m-%d %H:%M:%S") 表 $table 统计信息更新失败" >> $LOG_FILE
    fi
done

# 记录更新结束日志
echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL统计信息更新任务完成" >> $LOG_FILE
echo "-----------------------------------------------------------------" >> $LOG_FILE

性能优化脚本示例

性能优化脚本用于分析和优化TDSQL数据库的性能,帮助运维人员识别和解决性能问题。以下是两个常用的性能优化脚本示例:

1. 慢查询分析脚本

功能说明:使用pt-query-digest工具分析慢查询日志,生成慢查询报告。

使用场景:适用于定期慢查询分析,建议每周执行一次。

配置方法:修改脚本中的慢查询日志路径和分析报告路径。

注意事项:需要先安装pt-query-digest工具(percona-toolkit包的一部分)。

bash
#!/bin/bash
# TDSQL 慢查询分析脚本
# 功能:使用pt-query-digest分析慢查询日志
# 适用场景:定期慢查询分析

# 配置参数
SLOW_LOG_FILE="/var/lib/mysql/slow.log"  # 慢查询日志路径
ANALYSIS_LOG="/var/log/tdsql_slow_query_analysis.log"  # 分析报告路径
PT_QUERY_DIGEST="pt-query-digest"  # pt-query-digest工具路径

# 检查pt-query-digest工具是否存在
if [ ! -x "$(command -v $PT_QUERY_DIGEST)" ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") 错误:pt-query-digest工具未安装,请先安装percona-toolkit包" >> $ANALYSIS_LOG
    exit 1
fi

# 记录分析开始日志
echo "$(date +"%Y-%m-%d %H:%M:%S") 开始执行TDSQL慢查询分析..." >> $ANALYSIS_LOG

# 使用pt-query-digest分析慢查询日志
# pt-query-digest会生成详细的慢查询报告,包括:
# - 慢查询总数和总时间
# - 平均响应时间和最大响应时间
# - 慢查询按指纹分组统计
# - 慢查询执行计划分析
$PT_QUERY_DIGEST $SLOW_LOG_FILE >> $ANALYSIS_LOG

# 检查分析是否成功
if [ $? -eq 0 ]; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL慢查询分析完成" >> $ANALYSIS_LOG
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") TDSQL慢查询分析失败" >> $ANALYSIS_LOG
fi

echo "-----------------------------------------------------------------" >> $ANALYSIS_LOG

2. 索引使用情况脚本

功能说明:分析TDSQL数据库中索引的使用情况,识别未使用的索引和冗余索引。

使用场景:适用于定期索引优化,建议每季度执行一次。

配置方法:修改脚本中的数据库连接信息。

注意事项:需要启用performance_schema,否则无法获取索引使用情况。

python
#!/usr/bin/env python3
# TDSQL 索引使用情况分析脚本
# 功能:识别未使用的索引和冗余索引
# 适用场景:定期索引优化

import pymysql

# 配置参数
config = {
    'host': 'localhost',      # 数据库主机地址
    'port': 3306,             # 数据库端口
    'user': 'admin',          # 用户名,需具有管理员权限
    'password': 'password',    # 用户密码
    'database': 'information_schema'  # 连接的数据库
}

# 连接数据库
print("正在连接数据库...")
conn = pymysql.connect(**config)
cursor = conn.cursor()
print("数据库连接成功")

# 查询未使用的索引
def get_unused_indexes():
    """查询未使用的索引
    条件:
    1. 排除系统数据库
    2. 排除主键索引
    3. 索引使用次数为0或NULL
    """
    sql = """
    SELECT 
        t.TABLE_SCHEMA, 
        t.TABLE_NAME, 
        i.INDEX_NAME
    FROM 
        information_schema.TABLES t
    JOIN 
        information_schema.STATISTICS i ON t.TABLE_SCHEMA = i.TABLE_SCHEMA AND t.TABLE_NAME = i.TABLE_NAME
    LEFT JOIN 
        performance_schema.table_io_waits_summary_by_index_usage iu \
        ON t.TABLE_SCHEMA = iu.OBJECT_SCHEMA \
        AND t.TABLE_NAME = iu.OBJECT_NAME \
        AND i.INDEX_NAME = iu.INDEX_NAME
    WHERE 
        t.TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')
        AND i.INDEX_NAME != 'PRIMARY'
        AND (iu.COUNT_STAR IS NULL OR iu.COUNT_STAR = 0)
    ORDER BY 
        t.TABLE_SCHEMA, t.TABLE_NAME, i.INDEX_NAME
    """
    cursor.execute(sql)
    return cursor.fetchall()

# 查询冗余索引
def get_redundant_indexes():
    """查询冗余索引
    冗余索引定义:
    1. 两个索引的前缀列相同
    2. 或者一个索引是另一个索引的前缀
    """
    sql = """
    SELECT 
        s.TABLE_SCHEMA, 
        s.TABLE_NAME, 
        s.INDEX_NAME AS REDUNDANT_INDEX, 
        s.COLUMN_LIST AS REDUNDANT_COLUMNS, 
        d.INDEX_NAME AS DOMINANT_INDEX, 
        d.COLUMN_LIST AS DOMINANT_COLUMNS
    FROM (
        SELECT 
            TABLE_SCHEMA, 
            TABLE_NAME, 
            INDEX_NAME, 
            GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS COLUMN_LIST
        FROM 
            information_schema.STATISTICS
        GROUP BY 
            TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
    ) s
    JOIN (
        SELECT 
            TABLE_SCHEMA, 
            TABLE_NAME, 
            INDEX_NAME, 
            GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS COLUMN_LIST
        FROM 
            information_schema.STATISTICS
        GROUP BY 
            TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
    ) d ON s.TABLE_SCHEMA = d.TABLE_SCHEMA AND s.TABLE_NAME = d.TABLE_NAME AND s.INDEX_NAME != d.INDEX_NAME
    WHERE 
        s.TABLE_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')
        AND s.INDEX_NAME != 'PRIMARY' AND d.INDEX_NAME != 'PRIMARY'
        AND s.COLUMN_LIST LIKE CONCAT(d.COLUMN_LIST, '%')
        AND s.COLUMN_LIST != d.COLUMN_LIST
    """
    cursor.execute(sql)
    return cursor.fetchall()

# 主函数
def main():
    print("=== TDSQL 索引使用情况分析报告 ===")
    
    # 分析未使用的索引
    print("\n1. 未使用的索引:")
    print("   以下索引在监控期间未被使用,可考虑删除:")
    unused_indexes = get_unused_indexes()
    if not unused_indexes:
        print("   未发现未使用的索引")
    else:
        for schema, table, index_name in unused_indexes:
            print(f"   - {schema}.{table}: {index_name}")
    
    # 分析冗余索引
    print("\n2. 冗余索引:")
    print("   以下索引存在冗余,可考虑删除:")
    redundant_indexes = get_redundant_indexes()
    if not redundant_indexes:
        print("   未发现冗余索引")
    else:
        for schema, table, redundant_idx, redundant_cols, dominant_idx, dominant_cols in redundant_indexes:
            print(f"   - {schema}.{table}:")
            print(f"     冗余索引: {redundant_idx} ({redundant_cols})")
            print(f"     主导索引: {dominant_idx} ({dominant_cols})")
    
    print("\n=== 分析完成 ===")
    print("注意:")
    print("1. 删除索引前请先在测试环境验证")
    print("2. 考虑业务发展需求,避免误删未来可能使用的索引")
    print("3. 定期重新分析索引使用情况")

# 执行主函数
if __name__ == "__main__":
    main()
    # 关闭数据库连接
    cursor.close()
    conn.close()
    print("\n数据库连接已关闭")

常见问题(FAQ)

Q1: 如何编写安全的数据库脚本?

A1: 编写安全数据库脚本的方法包括:

  • 限制脚本执行权限
  • 避免硬编码敏感信息
  • 使用参数化查询,避免SQL注入
  • 最小权限原则:使用最小权限的数据库用户
  • 定期审查脚本安全性

Q2: 如何调试数据库脚本?

A2: 调试数据库脚本的方法包括:

  • 添加日志记录,输出关键信息
  • 使用调试工具,如Python的pdb
  • 在测试环境中逐步执行脚本
  • 检查数据库日志,了解执行情况

Q3: 如何自动化执行脚本?

A3: 自动化执行脚本的方法包括:

  • 使用cron定时执行脚本
  • 使用系统监控工具触发脚本执行
  • 使用自动化运维工具,如Ansible、SaltStack
  • 结合监控系统,实现事件触发执行

Q4: 如何处理脚本执行错误?

A4: 处理脚本执行错误的方法包括:

  • 添加错误处理机制,捕获和处理异常
  • 记录详细的错误日志
  • 实现脚本重试机制
  • 配置告警,及时通知运维人员

Q5: 如何优化脚本性能?

A5: 优化脚本性能的方法包括:

  • 减少数据库查询次数
  • 使用高效的查询语句
  • 避免在循环中执行数据库操作
  • 使用缓存机制,减少重复计算
  • 优化脚本的IO操作

脚本管理建议

1. 版本控制

  • 使用Git等版本控制系统管理脚本
  • 建立分支管理策略
  • 记录脚本变更历史

2. 文档化

  • 为每个脚本编写详细的文档
  • 说明脚本的功能、使用方法和注意事项
  • 记录脚本的变更历史

3. 测试管理

  • 在测试环境中充分测试脚本
  • 建立脚本测试用例
  • 定期回归测试

4. 部署管理

  • 使用自动化工具部署脚本
  • 建立脚本部署流程
  • 记录脚本部署历史

5. 监控管理

  • 监控脚本的执行状态
  • 记录脚本执行日志
  • 配置脚本执行告警