Files
nl-video-api/scripts/optimize_database.sql

376 lines
11 KiB
Go
Raw Normal View History

2025-08-03 00:11:15 +08:00
-- nl-video-api 数据库性能优化脚本
-- 执行前请备份数据库
-- ================================
-- 1. 索引优化
-- ================================
-- 用户表索引优化
ALTER TABLE `user` ADD INDEX `idx_username` (`username`);
ALTER TABLE `user` ADD INDEX `idx_phone` (`phone`);
ALTER TABLE `user` ADD INDEX `idx_email` (`email`);
ALTER TABLE `user` ADD INDEX `idx_status_vip` (`status`, `vip_level`);
ALTER TABLE `user` ADD INDEX `idx_created_at` (`created_at`);
ALTER TABLE `user` ADD INDEX `idx_last_login` (`last_login_at`);
-- 管理员表索引优化
ALTER TABLE `admin` ADD INDEX `idx_username` (`username`);
ALTER TABLE `admin` ADD INDEX `idx_email` (`email`);
ALTER TABLE `admin` ADD INDEX `idx_status` (`status`);
-- 影片表索引优化
ALTER TABLE `movie` ADD INDEX `idx_title` (`title`);
ALTER TABLE `movie` ADD INDEX `idx_type_category` (`type`, `category_id`);
ALTER TABLE `movie` ADD INDEX `idx_year` (`year`);
ALTER TABLE `movie` ADD INDEX `idx_country` (`country`);
ALTER TABLE `movie` ADD INDEX `idx_status` (`status`);
ALTER TABLE `movie` ADD INDEX `idx_rating` (`rating`);
ALTER TABLE `movie` ADD INDEX `idx_created_at` (`created_at`);
ALTER TABLE `movie` ADD INDEX `idx_updated_at` (`updated_at`);
-- 剧集表索引优化
ALTER TABLE `episode` ADD INDEX `idx_movie_id` (`movie_id`);
ALTER TABLE `episode` ADD INDEX `idx_episode_number` (`episode_number`);
ALTER TABLE `episode` ADD INDEX `idx_status` (`status`);
-- 分类表索引优化
ALTER TABLE `category` ADD INDEX `idx_parent_id` (`parent_id`);
ALTER TABLE `category` ADD INDEX `idx_sort` (`sort`);
ALTER TABLE `category` ADD INDEX `idx_status` (`status`);
-- 角色表索引优化
ALTER TABLE `role` ADD INDEX `idx_code` (`code`);
ALTER TABLE `role` ADD INDEX `idx_level` (`level`);
ALTER TABLE `role` ADD INDEX `idx_status` (`status`);
-- 权限表索引优化
ALTER TABLE `permission` ADD INDEX `idx_parent_id` (`parent_id`);
ALTER TABLE `permission` ADD INDEX `idx_type` (`type`);
ALTER TABLE `permission` ADD INDEX `idx_status` (`status`);
-- 角色权限关联表索引优化
ALTER TABLE `role_permission` ADD INDEX `idx_role_id` (`role_id`);
ALTER TABLE `role_permission` ADD INDEX `idx_permission_id` (`permission_id`);
-- ================================
-- 2. 表结构优化
-- ================================
-- 优化用户表字段类型
ALTER TABLE `user` MODIFY COLUMN `balance` DECIMAL(10,2) DEFAULT 0.00 COMMENT '余额';
ALTER TABLE `user` MODIFY COLUMN `points` INT UNSIGNED DEFAULT 0 COMMENT '积分';
ALTER TABLE `user` MODIFY COLUMN `vip_level` TINYINT UNSIGNED DEFAULT 0 COMMENT 'VIP等级';
-- 优化影片表字段类型
ALTER TABLE `movie` MODIFY COLUMN `rating` DECIMAL(3,1) DEFAULT 0.0 COMMENT '评分';
ALTER TABLE `movie` MODIFY COLUMN `duration` SMALLINT UNSIGNED DEFAULT 0 COMMENT '时长(分钟)';
ALTER TABLE `movie` MODIFY COLUMN `total_episodes` SMALLINT UNSIGNED DEFAULT 0 COMMENT '总集数';
-- 优化角色表字段类型
ALTER TABLE `role` MODIFY COLUMN `level` TINYINT UNSIGNED DEFAULT 1 COMMENT '角色等级';
ALTER TABLE `role` MODIFY COLUMN `sort` SMALLINT UNSIGNED DEFAULT 0 COMMENT '排序';
-- ================================
-- 3. 分区优化适用于大数据量
-- ================================
-- 用户表按注册时间分区年度分区
-- 注意分区需要在表创建时定义这里仅作为参考
/*
ALTER TABLE `user` PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
*/
-- ================================
-- 4. 查询优化视图
-- ================================
-- 创建用户统计视图
CREATE OR REPLACE VIEW `v_user_stats` AS
SELECT
COUNT(*) as total_users,
COUNT(CASE WHEN status = 1 THEN 1 END) as active_users,
COUNT(CASE WHEN vip_level > 0 THEN 1 END) as vip_users,
COUNT(CASE WHEN DATE(created_at) = CURDATE() THEN 1 END) as today_new_users,
AVG(balance) as avg_balance,
SUM(balance) as total_balance
FROM `user`;
-- 创建影片统计视图
CREATE OR REPLACE VIEW `v_movie_stats` AS
SELECT
COUNT(*) as total_movies,
COUNT(CASE WHEN type = 1 THEN 1 END) as movie_count,
COUNT(CASE WHEN type = 2 THEN 1 END) as tv_series_count,
COUNT(CASE WHEN status = 1 THEN 1 END) as published_count,
AVG(rating) as avg_rating,
COUNT(CASE WHEN DATE(created_at) = CURDATE() THEN 1 END) as today_new_movies
FROM `movie`;
-- 创建热门影片视图
CREATE OR REPLACE VIEW `v_popular_movies` AS
SELECT
m.id,
m.title,
m.type,
m.rating,
m.year,
c.name as category_name
FROM `movie` m
LEFT JOIN `category` c ON m.category_id = c.id
WHERE m.status = 1
ORDER BY m.rating DESC, m.created_at DESC;
-- ================================
-- 5. 存储过程优化
-- ================================
-- 用户余额更新存储过程
DELIMITER //
CREATE PROCEDURE `sp_update_user_balance`(
IN p_user_id INT,
IN p_amount DECIMAL(10,2),
IN p_type TINYINT,
IN p_remark VARCHAR(255)
)
BEGIN
DECLARE v_current_balance DECIMAL(10,2) DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
-- 获取当前余额
SELECT balance INTO v_current_balance FROM `user` WHERE id = p_user_id FOR UPDATE;
-- 检查余额是否足够扣款时
IF p_type = 2 AND v_current_balance < ABS(p_amount) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余额不足';
END IF;
-- 更新余额
IF p_type = 1 THEN
UPDATE `user` SET balance = balance + p_amount WHERE id = p_user_id;
ELSE
UPDATE `user` SET balance = balance - ABS(p_amount) WHERE id = p_user_id;
END IF;
-- 记录余额变动日志如果有日志表的话
-- INSERT INTO `balance_log` (user_id, amount, type, remark, created_at)
-- VALUES (p_user_id, p_amount, p_type, p_remark, NOW());
COMMIT;
END //
DELIMITER ;
-- VIP升级存储过程
DELIMITER //
CREATE PROCEDURE `sp_upgrade_user_vip`(
IN p_user_id INT,
IN p_vip_level TINYINT,
IN p_days INT
)
BEGIN
DECLARE v_current_vip_expire DATETIME;
DECLARE v_new_vip_expire DATETIME;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
-- 获取当前VIP到期时间
SELECT vip_expire_at INTO v_current_vip_expire FROM `user` WHERE id = p_user_id;
-- 计算新的到期时间
IF v_current_vip_expire IS NULL OR v_current_vip_expire < NOW() THEN
SET v_new_vip_expire = DATE_ADD(NOW(), INTERVAL p_days DAY);
ELSE
SET v_new_vip_expire = DATE_ADD(v_current_vip_expire, INTERVAL p_days DAY);
END IF;
-- 更新用户VIP信息
UPDATE `user` SET
vip_level = p_vip_level,
vip_expire_at = v_new_vip_expire,
updated_at = NOW()
WHERE id = p_user_id;
COMMIT;
END //
DELIMITER ;
-- ================================
-- 6. 数据清理和维护
-- ================================
-- 清理过期的VIP用户
UPDATE `user` SET vip_level = 0 WHERE vip_expire_at < NOW() AND vip_level > 0;
-- 清理软删除的数据超过30天
DELETE FROM `movie` WHERE deleted_at IS NOT NULL AND deleted_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
DELETE FROM `user` WHERE deleted_at IS NOT NULL AND deleted_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- ================================
-- 7. 性能监控查询
-- ================================
-- 查看慢查询日志状态
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
-- 查看索引使用情况
SELECT
TABLE_SCHEMA,
TABLE_NAME,
INDEX_NAME,
CARDINALITY,
SUB_PART,
PACKED,
NULLABLE,
INDEX_TYPE
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'nl_video_db'
ORDER BY TABLE_NAME, INDEX_NAME;
-- 查看表大小和行数
SELECT
TABLE_NAME,
TABLE_ROWS,
ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024), 2) AS 'Size(MB)',
ROUND((DATA_LENGTH / 1024 / 1024), 2) AS 'Data(MB)',
ROUND((INDEX_LENGTH / 1024 / 1024), 2) AS 'Index(MB)'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'nl_video_db'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;
-- ================================
-- 8. 配置优化建议
-- ================================
/*
MySQL配置优化建议my.cnf
[mysqld]
# 基础配置
default-storage-engine = InnoDB
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 内存配置
innodb_buffer_pool_size = 1G # 设置为物理内存的70-80%
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
key_buffer_size = 256M
max_connections = 500
thread_cache_size = 50
# 查询缓存
query_cache_type = 1
query_cache_size = 256M
query_cache_limit = 2M
# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# InnoDB配置
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_open_files = 400
# 临时表配置
tmp_table_size = 256M
max_heap_table_size = 256M
# 排序和连接配置
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 1M
*/
-- ================================
-- 9. 定期维护脚本
-- ================================
-- 创建定期维护事件
DELIMITER //
CREATE EVENT IF NOT EXISTS `ev_daily_maintenance`
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO
BEGIN
-- 更新过期VIP用户
UPDATE `user` SET vip_level = 0 WHERE vip_expire_at < NOW() AND vip_level > 0;
-- 优化表
OPTIMIZE TABLE `user`;
OPTIMIZE TABLE `movie`;
OPTIMIZE TABLE `episode`;
-- 分析表
ANALYZE TABLE `user`;
ANALYZE TABLE `movie`;
ANALYZE TABLE `episode`;
-- 记录维护日志
INSERT INTO `system_log` (type, message, created_at)
VALUES ('maintenance', 'Daily maintenance completed', NOW());
END //
DELIMITER ;
-- 启用事件调度器
SET GLOBAL event_scheduler = ON;
-- ================================
-- 10. 备份建议
-- ================================
/*
数据库备份脚本示例
#!/bin/bash
# 数据库备份脚本
DB_NAME="nl_video_db"
DB_USER="root"
DB_PASS="password"
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
# 创建备份目录
mkdir -p $BACKUP_DIR
# 全量备份
mysqldump -u$DB_USER -p$DB_PASS --single-transaction --routines --triggers $DB_NAME > $BACKUP_DIR/full_backup_$DATE.sql
# 压缩备份文件
gzip $BACKUP_DIR/full_backup_$DATE.sql
# 删除7天前的备份
find $BACKUP_DIR -name "full_backup_*.sql.gz" -mtime +7 -delete
echo "Backup completed: full_backup_$DATE.sql.gz"
*/
-- ================================
-- 执行完成提示
-- ================================
SELECT 'Database optimization completed successfully!' as message;
SELECT 'Please restart MySQL service to apply configuration changes.' as note;
SELECT 'Run SHOW PROCESSLIST; to monitor current queries.' as monitoring_tip;