首页 / 资讯中心 / 文章详情

SQL增删改查实战:从基础到性能优化

SQL增删改查实战:从基础到性能优化 ★ FEATURED ARTICLE
1. SQL增删改查基础操作全解析作为数据库操作的核心技能增删改查CRUD是每个开发者必须掌握的看家本领。我在金融、电商等多个行业的数据库开发中见证了无数新人因为基础不牢导致的性能问题和数据事故。本文将用真实项目中的经验教训带你重新认识这些简单操作背后的门道。2. 环境准备与数据表示例2.1 测试环境搭建建议使用MySQL 8.0或SQL Server 2019进行实操这两个版本对标准SQL的支持最完善。避免使用图形化工具直接操作先用命令行培养SQL语感# MySQL安装后登录 mysql -u root -p # 创建练习数据库 CREATE DATABASE crud_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;2.2 示例表结构设计我们设计一个电商用户表包含典型的数据类型和约束CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password CHAR(60) NOT NULL COMMENT 存储bcrypt哈希值, email VARCHAR(100) UNIQUE, age TINYINT UNSIGNED CHECK (age 18), balance DECIMAL(12,2) DEFAULT 0.00, status ENUM(active,frozen,deleted) DEFAULT active, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB;注意密码字段必须使用单向哈希存储实际项目中绝对禁止明文保存密码3. 增删改查深度解析3.1 插入数据INSERT3.1.1 基础插入操作-- 最简形式需按字段顺序 INSERT INTO users VALUES(NULL, john_doe, $2a$10$x..., johnexample.com, 25, 100.00, DEFAULT, NULL, NULL); -- 推荐写法明确字段对应关系 INSERT INTO users (username, password, email, age) VALUES (alice, $2a$10$y..., aliceexample.com, 30);3.1.2 批量插入性能优化单条插入在需要插入大量数据时效率极低。实测显示批量插入速度可提升10倍以上-- 多值列表插入 INSERT INTO users (username, password) VALUES (user1, $2a$10$1...), (user2, $2a$10$2...), (user3, $2a$10$3...); -- 事务包裹插入SQL Server语法 BEGIN TRANSACTION; INSERT INTO users (...) VALUES (...); INSERT INTO users (...) VALUES (...); COMMIT;踩坑记录曾有个项目因未使用批量插入导致用户导入耗时45分钟改用批量后仅需28秒3.2 查询数据SELECT3.2.1 基础查询与条件过滤-- 基本查询 SELECT * FROM users WHERE status active; -- 分页查询MySQL语法 SELECT user_id, username FROM users WHERE age 20 ORDER BY created_at DESC LIMIT 10 OFFSET 0; -- 第一页 -- 分页查询SQL Server语法 SELECT TOP 10 user_id, username FROM users WHERE age 20 ORDER BY created_at DESC;3.2.2 高级查询技巧-- 聚合函数与分组 SELECT status, COUNT(*) AS user_count, AVG(age) AS avg_age, SUM(balance) AS total_balance FROM users GROUP BY status HAVING COUNT(*) 5; -- 窗口函数分析用户余额排名 SELECT user_id, username, balance, RANK() OVER (ORDER BY balance DESC) AS wealth_rank FROM users;3.3 更新数据UPDATE3.3.1 单表更新-- 基础更新 UPDATE users SET status frozen WHERE user_id 5; -- 带计算的更新 UPDATE users SET balance balance 50.00 WHERE status active AND created_at 2023-01-01;3.3.2 多表关联更新-- 根据订单表更新用户余额MySQL语法 UPDATE users u JOIN ( SELECT user_id, SUM(amount) AS total FROM orders WHERE status completed GROUP BY user_id ) o ON u.user_id o.user_id SET u.balance u.balance o.total;血泪教训永远先写WHERE条件再执行UPDATE有次生产环境误操作全表更新导致半小时服务不可用3.4 删除数据DELETE3.4.1 基础删除操作-- 条件删除 DELETE FROM users WHERE status deleted AND updated_at DATE_SUB(NOW(), INTERVAL 30 DAY); -- 全表删除极度危险 TRUNCATE TABLE audit_logs; -- 比DELETE更快且不可回滚3.4.2 软删除实践实际项目中推荐使用软删除而非物理删除-- 添加is_deleted字段替代物理删除 ALTER TABLE users ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE; -- 标记删除而非实际删除 UPDATE users SET is_deleted TRUE WHERE user_id 10; -- 查询时排除已删除数据 SELECT * FROM users WHERE is_deleted FALSE;4. 安全防护与性能优化4.1 防止SQL注入4.1.1 参数化查询示例# Python中使用参数化查询 cursor.execute( SELECT * FROM users WHERE username %s AND password %s, (username_input, password_hash) )4.1.2 输入验证策略白名单验证对枚举类型字段检查输入是否在预定义范围内类型转换将输入强制转换为预期类型如intval($_GET[id])正则过滤对字符串输入使用正则表达式验证格式4.2 查询性能优化4.2.1 索引使用原则-- 为常用查询条件创建索引 CREATE INDEX idx_users_status ON users(status); CREATE INDEX idx_users_created ON users(created_at); -- 复合索引最左匹配原则 CREATE INDEX idx_users_search ON users(status, age, created_at); -- 能使用该索引的查询 -- WHERE status ? -- WHERE status ? AND age ? -- WHERE status ? AND age ? AND created_at ?4.2.2 EXPLAIN分析实战EXPLAIN SELECT * FROM users WHERE status active ORDER BY created_at DESC LIMIT 10; -- 理想输出应显示 -- type: ref -- key: idx_users_status -- Extra: Using where; Using filesort如出现Using filesort需优化5. 事务处理与并发控制5.1 基础事务示例START TRANSACTION; UPDATE accounts SET balance balance - 100 WHERE user_id 1; UPDATE accounts SET balance balance 100 WHERE user_id 2; -- 检查业务规则 SELECT IF( (SELECT balance FROM accounts WHERE user_id 1) 0, COMMIT, ROLLBACK ) INTO action; IF action COMMIT THEN COMMIT; ELSE ROLLBACK; END IF;5.2 隔离级别选择-- 查看当前隔离级别MySQL SELECT transaction_isolation; -- 设置隔离级别针对敏感操作 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; -- 资金核对操作... COMMIT;6. 实战案例用户管理系统CRUD6.1 完整用户注册流程DELIMITER // CREATE PROCEDURE register_user( IN p_username VARCHAR(50), IN p_password VARCHAR(60), IN p_email VARCHAR(100), IN p_age INT ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; -- 检查用户名唯一性 IF EXISTS (SELECT 1 FROM users WHERE username p_username) THEN SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT Username already exists; END IF; -- 插入新用户 INSERT INTO users (username, password, email, age) VALUES (p_username, p_password, p_email, p_age); -- 创建用户配置记录 INSERT INTO user_settings (user_id) VALUES (LAST_INSERT_ID()); COMMIT; END // DELIMITER ;6.2 数据归档清理作业-- 每月执行的归档脚本 BEGIN -- 将6个月前的日志移到历史表 INSERT INTO user_logs_archive SELECT * FROM user_logs WHERE created_at DATE_SUB(NOW(), INTERVAL 6 MONTH); -- 删除已归档数据 DELETE FROM user_logs WHERE created_at DATE_SUB(NOW(), INTERVAL 6 MONTH); -- 优化表空间 OPTIMIZE TABLE user_logs; END7. 开发调试技巧7.1 SQL日志分析-- MySQL开启通用日志开发环境 SET GLOBAL general_log ON; SET GLOBAL log_output TABLE; -- 查看执行日志 SELECT * FROM mysql.general_log WHERE argument LIKE %users% ORDER BY event_time DESC LIMIT 10;7.2 性能监控-- 查看慢查询需先开启慢查询日志 SELECT * FROM performance_schema.events_statements_summary_by_digest ORDER BY avg_timer_wait DESC LIMIT 5;在金融级项目实践中我们发现80%的SQL性能问题都源于未合理使用索引或N1查询问题。一个典型的优化案例是将某个耗时1200ms的报表查询通过重构为JOIN窗口函数的方式降低到87ms。记住数据库操作没有差不多每个字节和毫秒的优化都可能影响百万级用户的体验。
阅读完成 · 觉得有帮助?
咨询建站