376 lines
11 KiB
Go
376 lines
11 KiB
Go
|
|
-- 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;
|