-
一、查询SQLSELECT t1.规则编号 AS 编码, t1.规则描述 AS 名称, SUM( CASE WHEN t3.DATA_SOURCES = '00' THEN 1 ELSE 0 END ) AS '类型01', SUM( CASE WHEN t3.DATA_SOURCES = '01' THEN 1 ELSE 0 END ) AS '类型02', SUM( CASE WHEN t3.DATA_SOURCES = '02' THEN 1 ELSE 0 END ) AS '类型03', SUM( CASE WHEN t3.DATA_SOURCES = '03' THEN 1 ELSE 0 END ) AS '类型04' FROM (SELECT 'A_M_0001' AS 规则编号, '规则01' AS 规则描述 UNION ALLSELECT 'A_M_0002' AS 规则编号, '规则02' AS 规则描述 UNION ALLSELECT 'A_M_0003' AS 规则编号, '规则03' AS 规则描述 UNION ALLSELECT 'A_M_0005' AS 规则编号, '规则04' AS 规则描述 UNION ALLSELECT 'A_M_0007' AS 规则编号, '规则05' AS 规则描述 UNION ALLSELECT 'A_M_0006' AS 规则编号, '规则06' AS 规则描述 UNION ALLSELECT 'A_M_0008' AS 规则编号, '规则07' AS 规则描述 UNION ALLSELECT 'A_J_0001_01' AS 规则编号, '规则08' AS 规则描述 UNION ALLSELECT 'A_J_0001_12' AS 规则编号, '规则09' AS 规则描述 UNION ALLSELECT 'A_J_0001_02' AS 规则编号, '规则10' AS 规则描述 UNION ALLSELECT 'A_J_0001_03' AS 规则编号, '规则11' AS 规则描述 UNION ALLSELECT 'A_J_0001_13' AS 规则编号, '规则12' AS 规则描述 UNION ALLSELECT 'A_J_0001_05' AS 规则编号, '规则13' AS 规则描述 UNION ALLSELECT 'A_J_0001_11' AS 规则编号, '规则14' AS 规则描述 UNION ALLSELECT 'A_J_0001_06' AS 规则编号, '规则15' AS 规则描述 UNION ALLSELECT 'A_J_0001_14' AS 规则编号, '规则16' AS 规则描述 UNION ALLSELECT 'A_J_0001_07' AS 规则编号, '规则17' AS 规则描述 UNION ALLSELECT 'A_J_0001_15' AS 规则编号, '规则18' AS 规则描述 UNION ALLSELECT 'A_J_0002_01' AS 规则编号, '规则19' AS 规则描述 UNION ALLSELECT 'A_J_0002_02' AS 规则编号, '规则20' AS 规则描述 UNION ALLSELECT 'A_J_0002_03' AS 规则编号, '规则21' AS 规则描述 UNION ALLSELECT 'A_J_0002_04' AS 规则编号, '规则22' AS 规则描述 UNION ALLSELECT 'A_J_0002_05' AS 规则编号, '规则23' AS 规则描述 UNION ALLSELECT 'A_J_0002_06' AS 规则编号, '规则24' AS 规则描述 UNION ALLSELECT 'A_J_0002_07' AS 规则编号, '规则25' AS 规则描述 UNION ALLSELECT 'A_J_0003_01' AS 规则编号, '规则26' AS 规则描述 UNION ALLSELECT 'A_J_0003_02' AS 规则编号, '规则27' AS 规则描述 UNION ALLSELECT 'A_J_0003_05' AS 规则编号, '规则28' AS 规则描述 ) t1 LEFT JOIN RAMS_TRIAL_CHECKLIST t2 ON t2.RULE_CODE like concat('%',t1.规则编号,'%') LEFT JOIN RAMS_TRIAL_CHECKLIST_EXT t3 ON t2.CHECKLIST_ID = t3.CHECKLIST_ID WHERE DATE( t2.UPDATE_TIME ) = CURDATE( ) - INTERVAL 1 DAY GROUP BY t1.规则编号,t1.规则描述;二、查询结果三、总结1.数据库表中不存在的字段,可以利用以下sql进行处理:SELECT '60019311' AS code, '北京' AS nameunion allSELECT '60019312' AS code, '上海' AS nameunion allSELECT '60019313' AS code, '广州' AS nameunion allSELECT '60019314' AS code, '重庆' AS name2.两表关联查询,利用【Like】进行条件关联:RAMS_TRIAL_CHECKLIST t2 ON t2.RULE_CODE like concat('%',t1.规则编号,'%')3.case when sql语句:CASE WHEN t3.DATA_SOURCES = '00' THEN 1 ELSE 0 END4.查询系统当前时间的前一天数据的数量:SELECT COUNT(ID) FROM DATA WHERE DATE( UPDATE_TIME ) = CURDATE( ) - INTERVAL 1 DAY转载自https://www.cnblogs.com/songweipeng/p/18663663
-
问题描述这是关系型数据库中字符串存储类型的经典面试题面试官通过这个问题考察对数据库底层存储原理的理解通常会追问使用场景和性能影响核心答案CHAR和VARCHAR的主要区别:存储方式CHAR:固定长度存储,不足部分用空格填充VARCHAR:可变长度存储,根据实际内容长度分配空间存储空间CHAR(n):总是占用n个字符的空间VARCHAR(n):只占用实际字符长度+1或2个字节的额外空间(用于记录长度)性能特点CHAR:读写性能较稳定,适合固定长度数据VARCHAR:空间利用率高,适合变长数据详细解析1. CHAR特点它的特点为固定长度(最大255字符)、存储时空格填充到指定长度、检索时默认删除尾部空格、适合存储长度变化很小的数据2. VARCHAR特点它的特点为可变长度(MySQL 5.0.3之后最多可达65,535字节)、存储时需要1-2个字节记录长度、检索时不删除尾部空格、长度小于255使用1字节存储长度信息,否则使用2字节。需要注意的是在频繁更新的列上可能导致碎片化常见追问Q1: 什么场景下选择CHAR?A:存储长度几乎相等的字符串(如:邮政编码、手机号码)经常更新的字段(避免碎片)短字符串且长度固定(如:Y/N标识)频繁访问的表(减少碎片,提高性能)Q2: 什么场景下选择VARCHAR?A:存储变长数据(如:名称、地址、评论等)列的最大长度比平均长度大很多列很少被更新使用UTF-8等多字节字符集(节省空间)Q3: 两者在性能上有什么差异?A:CHAR:写入性能稍好(不需要计算长度)读取性能稍好(固定长度寻址更快)适合频繁更新的场景(减少碎片)VARCHAR:空间利用率高(适合大量数据)对于非常长的文本比CHAR更高效表更新时可能产生碎片,需要定期优化扩展知识存储示例输入CHAR(10)存储实际占用VARCHAR(10)存储实际占用‘Hello’'Hello ’10字节‘Hello’6字节(5+1)‘Hi’'Hi ’10字节‘Hi’3字节(2+1)‘HelloWorld’‘HelloWorld’10字节‘HelloWorld’11字节(10+1)CHAR和VARCHAR在不同数据库中的实现差异MySQL: CHAR最大255字符,VARCHAR最大65535字节SQL Server: CHAR最大8000字节,VARCHAR最大8000字节,VARCHAR(MAX)最大2GBOracle: CHAR最大2000字节,VARCHAR2最大4000字节实际应用示例场景一:用户信息表CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR(50), -- 用户名变长 gender CHAR(1), -- M或F,固定长度 phone CHAR(11), -- 手机号,固定长度 address VARCHAR(200) -- 地址变长 ); 场景二:产品编码表CREATE TABLE products ( product_code CHAR(8), -- 固定长度产品编码 product_name VARCHAR(100), -- 变长产品名称 description VARCHAR(1000) -- 变长描述 ); 总结CHAR适合固定长度、频繁更新的短字符串VARCHAR适合变长字符串,节省存储空间选择取决于数据特性、访问模式和存储需求性能优化需考虑存储空间和访问效率的平衡面试技巧先说明基本区别(固定长度vs可变长度)描述各自的优缺点和适用场景结合实际例子说明选择依据提到不同数据库的实现差异展示深度
-
问题描述• 这是数据库领域中比较基础的面试题。• 面试官可能会通过这个问题考察你对数据库基础知识的理解,并根据二者的特性进行进一步追问。核心答案1. 数据存储方式▫ 关系型:以表格形式存储,数据之间有关联关系。▫ 非关系型:以键值对、文档、列族等形式存储,更灵活。2. 数据结构▫ 关系型:固定的表结构,需要预先定义 schema。▫ 非关系型:灵活的数据结构,可以动态调整。3. 扩展性▫ 关系型:垂直扩展(增加服务器性能)。▫ 非关系型:水平扩展(增加服务器数量)。详细解析关系型数据库的特点• 常见产品有:MySQL、Oracle、PostgreSQL。• 主要优势:强一致性、支持复杂查询、事务完善。• 缺点:扩展性受限、处理大数据量时性能下降、结构固定不够灵活。非关系型数据库的特点• 主要产品有:Redis、MongoDB 等。• 主要优势:高扩展性、高性能、灵活的数据模型。• 缺点:一致性较弱、复杂查询支持有限、事务支持不完善。常见追问Q1:什么场景下选择关系型数据库? A:需要强一致性的业务(如银行交易)、需要复杂查询的场景、数据结构相对固定的应用。Q2:什么场景下选择非关系型数据库? A:需要处理大量数据、需要快速读写、数据结构经常变化的场景。
-
一、B+树索引核心原理深度解析1. B+树的结构特性MySQL的InnoDB存储引擎采用B+树作为索引的基础数据结构,其核心特点包括:多路平衡搜索树:保持数据有序且查询路径长度均衡叶子节点链表:所有数据存储在叶子节点,并通过双向链表连接非叶子节点仅存键值:内部节点只存储索引键和子节点指针高扇出特性:单个节点可存储大量键值(通常500-1000)B+树的这种结构使其具有O(logN)的查询复杂度,且范围查询效率极高。实测表明,在千万级数据表中,通过B+树索引只需3-4次磁盘I/O即可定位到目标数据。2. InnoDB索引实现细节InnoDB中索引分为两大类:聚簇索引:叶子节点存储完整数据记录(按主键组织)二级索引:叶子节点存储主键值(需回表查询)-- 聚簇索引结构示例(表定义) CREATE TABLE users ( id INT PRIMARY KEY, -- 聚簇索引键 name VARCHAR(100), age INT, INDEX idx_age (age) -- 二级索引 ); 关键性能指标:单个页大小16KB(可通过innodb_page_size调整)每个索引记录约20-30字节开销(头信息+指针)三层B+树可支撑约2000万条记录(假设每页100条记录)二、索引设计黄金法则1. 索引选择策略高选择性字段优先:-- 低选择性示例(不推荐) ALTER TABLE employees ADD INDEX idx_gender (gender); -- 高选择性示例(推荐) ALTER TABLE employees ADD INDEX idx_employee_id (employee_id); 组合索引设计原则(最左前缀法则):-- 有效利用组合索引的查询 SELECT * FROM orders WHERE user_id=100 AND status='paid'; -- 对应的最优索引 ALTER TABLE orders ADD INDEX idx_user_status (user_id, status); 覆盖索引优化:-- 避免回表的查询设计 SELECT user_id, status FROM orders WHERE user_id=100; -- 只需扫描索引,无需访问数据行 2. 索引失效的八大陷阱及解决方案隐式类型转换:-- 失效案例(phone是varchar类型) SELECT * FROM users WHERE phone=13800138000; -- 解决方案 SELECT * FROM users WHERE phone='13800138000'; 索引列参与运算:-- 失效案例 SELECT * FROM accounts WHERE YEAR(create_time)=2023; -- 解决方案 SELECT * FROM accounts WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'; 前导模糊查询:-- 失效案例 SELECT * FROM products WHERE name LIKE '%手机%'; -- 解决方案(考虑全文索引) ALTER TABLE products ADD FULLTEXT INDEX ft_name (name); OR条件不当使用:-- 失效案例 SELECT * FROM logs WHERE id=100 OR operation='delete'; -- 解决方案 SELECT * FROM logs WHERE id=100 UNION ALL SELECT * FROM logs WHERE operation='delete' AND id!=100; 不符合最左前缀:-- 对INDEX(a,b,c) WHERE b=1 AND c=2 -- 失效 WHERE a=1 AND c=2 -- 部分有效(a) 使用NOT、!=、<>:-- 失效案例 SELECT * FROM orders WHERE status!='paid'; -- 解决方案(考虑范围查询) SELECT * FROM orders WHERE status IN ('unpaid','canceled'); 函数操作索引列:-- 失效案例 SELECT * FROM users WHERE LEFT(name,3)='张'; -- 解决方案 SELECT * FROM users WHERE name LIKE '张%'; JOIN字段类型不匹配:-- 失效案例(users.id是INT,orders.user_id是VARCHAR) SELECT * FROM users JOIN orders ON users.id=orders.user_id; 三、高级优化实战技巧1. 索引跳跃扫描(Index Skip Scan)MySQL 8.0+引入的优化技术,当组合索引前导列区分度低时可发挥作用:-- 对INDEX(gender,age) SELECT * FROM employees WHERE age>30; -- 8.0+可以拆解为: SELECT * FROM employees WHERE gender='M' AND age>30 UNION ALL SELECT * FROM employees WHERE gender='F' AND age>30; 2. 索引条件下推(ICP)MySQL 5.6+特性,将WHERE条件推到存储引擎层过滤:-- 对INDEX(zipcode, lastname) SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%'; -- ICP允许在索引中直接过滤lastname 3. 索引合并优化MySQL能将多个索引扫描结果合并:-- 对INDEX(a), INDEX(b) SELECT * FROM table WHERE a=1 OR b=2; -- 可能使用Index Merge算法 四、性能监控与调优工具1. 核心诊断命令-- 查看索引使用情况 EXPLAIN SELECT * FROM orders WHERE user_id=100; -- 更详细的分析 EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id=100; -- 索引统计信息 SHOW INDEX FROM orders; -- 查看未使用索引 SELECT * FROM sys.schema_unused_indexes; 2. 性能监控指标-- 关键性能计数器 SHOW STATUS LIKE 'Handler_read%'; -- InnoDB索引状态 SHOW ENGINE INNODB STATUS; -- 慢查询分析 SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10; 五、真实业务场景优化案例案例1:电商订单查询优化问题:千万级订单表按用户ID+时间范围查询缓慢SELECT * FROM orders WHERE user_id=12345 AND create_time BETWEEN '2023-01-01' AND '2023-12-31'; 优化方案:创建组合索引(user_id, create_time)改写查询为:SELECT * FROM orders FORCE INDEX(idx_user_time) WHERE user_id=12345 AND create_time >= '2023-01-01' AND create_time < '2024-01-01'; 添加查询缓存效果:查询时间从2.3秒降至0.02秒案例2:社交平台好友动态查询问题:好友动态feed流查询性能差SELECT * FROM posts WHERE user_id IN (SELECT friend_id FROM relations WHERE user_id=100) ORDER BY create_time DESC LIMIT 20; 优化方案:为relations表添加(user_id, friend_id)索引为posts表添加(user_id, create_time)索引改写为JOIN查询:SELECT p.* FROM posts p JOIN relations r ON p.user_id=r.friend_id WHERE r.user_id=100 ORDER BY p.create_time DESC LIMIT 20; 效果:响应时间从1.8秒降至0.15秒六、MySQL 8.0索引新特性隐藏索引:可标记索引为"不可见"进行测试ALTER TABLE orders ALTER INDEX idx_test INVISIBLE; 降序索引:优化DESC排序查询CREATE INDEX idx_time_desc ON logs(create_time DESC); 函数索引:直接对表达式建立索引CREATE INDEX idx_name_lower ON users((LOWER(name))); JSON索引:支持JSON文档路径索引CREATE INDEX idx_profile_location ON users( (CAST(profile->'$.address.city' AS CHAR(20))) ); 七、索引维护最佳实践定期分析表:ANALYZE TABLE orders; 碎片整理策略:-- 在线重建表(5.6+) ALTER TABLE orders ENGINE=InnoDB; -- 优化表(会锁表) OPTIMIZE TABLE orders; 索引监控周期:高频更新表:每周检查索引使用率低频更新表:每月检查即可大促前必须进行专项检查删除冗余索引工具:pt-index-usage /var/lib/mysql/mysql-slow.logMySQL索引优化是一门需要理论结合实践的艺术。理解B+树的工作原理是基础,掌握索引失效的黄金法则能避免常见陷阱,而持续的性能监控和适时调整则是保持数据库高效运行的关键。随着MySQL 8.0等新版本的推出,索引功能不断增强,为DBA和开发者提供了更多优化武器。记住:没有放之四海皆准的最优索引方案,只有最适合当前业务场景的索引设计。
-
一、Change Buffer的基本概念Change Buffer是InnoDB存储引擎中一项关键的写优化技术,它作为Buffer Pool的一部分,专门用于缓存对非唯一二级索引的变更操作(INSERT、UPDATE、DELETE)。当这些索引页不在内存中时,Change Buffer会暂存这些变更,等到相关索引页被加载到Buffer Pool时再合并(Merge)这些变更。从MySQL 5.5版本开始,这项技术从最初的"Insert Buffer"(仅优化INSERT操作)扩展为"Change Buffer",支持对UPDATE和DELETE操作的优化。在默认配置下,Change Buffer最多可占用Buffer Pool空间的25%(通过参数innodb_change_buffer_max_size可调整,最大允许50%)。二、Change Buffer的核心工作原理1. 写操作加速机制当执行针对非唯一二级索引的DML操作时,InnoDB会按以下逻辑处理:检查索引页是否在Buffer Pool:如果在:直接修改索引页如果不在:将变更记录到Change Buffer延迟合并(Merge):当该索引页后续被读取到Buffer Pool时或系统空闲时或Change Buffer空间不足时或数据库关闭前批量应用变更:将积累的多个变更一次性应用到索引页2. 数据结构实现Change Buffer本质上是一个B+树结构,存储在系统表空间(ibdata1)中,包含以下关键信息:空间ID(space ID)页号(page number)变更类型(insert/delete-mark/delete)变更的具体数据这种设计使得Change Buffer本身也能高效地进行查找和插入操作。三、Change Buffer的性能优势1. 显著减少随机I/O传统方式下,修改一个不在内存中的索引页需要:从磁盘读取索引页到内存(1次随机I/O)修改内存中的页写入redo log使用Change Buffer后:只需写入Change Buffer(内存操作)写入redo log(保护Change Buffer内容)避免了昂贵的磁盘随机读取操作,对于机械硬盘(HDD)尤其有效。2. 批量处理带来的效率提升Change Buffer积累多个变更后一次性应用,具有显著的批处理优势:减少同一页的多次修改为一次物理写入合并相邻键的插入操作减少索引页的分裂次数测试表明,在高并发写入场景下,使用Change Buffer可使写入性能提升5-10倍。四、Change Buffer的适用场景与限制1. 最佳适用场景非唯一二级索引:Change Buffer只对非唯一索引有效写密集型应用:INSERT/UPDATE/DELETE频繁的系统索引页不在内存中:当工作集远大于Buffer Pool时效果更明显机械硬盘环境:随机I/O代价高的存储介质2. 使用限制与注意事项唯一性约束:唯一索引必须立即检查唯一性,无法使用Change Buffer内存占用:默认最大占用Buffer Pool的25%,需权衡内存使用崩溃恢复:Change Buffer内容受redo log保护,但故障时未合并的变更会增加恢复时间监控指标:通过SHOW ENGINE INNODB STATUS可查看Change Buffer使用情况五、Change Buffer的配置与优化1. 关键配置参数-- Change Buffer最大占比(默认25,范围0-50) SET GLOBAL innodb_change_buffer_max_size=30; -- 监控Change Buffer使用情况 SHOW VARIABLES LIKE 'innodb_change_buffer_max_size'; 2. 优化建议合理设置大小:写密集型应用:可适当增大(30-40)读密集型应用:可适当减小(10-20)监控与调整:-- 查看Change Buffer状态 SHOW ENGINE INNODB STATUS\G关注输出中的INSERT BUFFER AND ADAPTIVE HASH INDEX部分特殊场景处理:批量导入数据时可临时增大Change Buffer报表查询前可主动触发合并:ANALYZE TABLE六、Change Buffer与其他缓冲机制的对比特性Change BufferBuffer PoolDouble Write Buffer主要目的加速非唯一索引写缓存数据页防止页写入不完整存储内容索引变更记录数据页和索引页数据页副本持久化方式系统表空间+redo不直接持久化独立文件内存占用Buffer Pool部分主内存区域独立内存区域适用操作INSERT/UPDATE/DELETE所有操作写操作七、实际案例分析某电商平台商品搜索系统在使用Change Buffer优化前后的对比:优化前:每秒约5,000次商品更新操作磁盘I/O利用率持续90%+平均写入延迟15ms优化后(调整innodb_change_buffer_max_size=35):相同负载下磁盘I/O降至40%平均写入延迟降至3ms系统吞吐量提升3倍但至少在目前,Change Buffer仍然是InnoDB在高并发写入场景下不可或缺的优化手段,理解其原理和适用场景对于数据库性能调优至关重要。
-
事务是数据库管理系统的核心概念之一,也是确保数据一致性和完整性的关键技术。本文将全面剖析MySQL事务的实现机制、特性及应用场景。一、事务基础概念1. 什么是事务事务(Transaction)是数据库操作的最小工作单元,是一组不可分割的SQL操作序列,这些操作要么全部执行成功,要么全部不执行。事务具有以下四个关键特性(ACID):原子性(Atomicity):事务是不可分割的工作单位一致性(Consistency):事务执行前后数据库状态必须一致隔离性(Isolation):并发事务之间互不干扰持久性(Durability):事务提交后结果永久保存2. MySQL事务语句-- 显式事务控制START TRANSACTION; -- 或 BEGIN[SQL语句1][SQL语句2]...COMMIT; -- 提交事务-- 或ROLLBACK; -- 回滚事务-- 设置自动提交SET autocommit = 0; -- 关闭自动提交(1为开启)二、事务隔离级别详解1. 四种隔离级别隔离级别脏读不可重复读幻读性能READ UNCOMMITTED可能可能可能最高READ COMMITTED不可能可能可能高REPEATABLE READ(MySQL默认)不可能不可能可能*中SERIALIZABLE不可能不可能不可能低*注:MySQL的InnoDB在REPEATABLE READ下通过MVCC+间隙锁可避免大部分幻读2. 隔离级别设置与查看-- 查看当前隔离级别SELECT @@transaction_isolation;-- 设置会话级隔离级别SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 设置全局级隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;三、MySQL事务实现原理1. 原子性实现:Undo Log作用:记录事务修改前的数据状态原理:事务开始前将修改前的数据写入Undo Log回滚时根据Undo Log恢复原始数据提交后Undo Log不会立即删除,用于MVCC2. 持久性实现:Redo Log作用:确保事务提交后数据不丢失原理:采用WAL(Write-Ahead Logging)机制事务提交前先将修改写入Redo Log系统崩溃恢复时重放Redo Log事务开始数据修改写入Undo Log写入Redo Log BufferRedo Log刷盘事务提交3. 隔离性实现:MVCC+锁机制(1) MVCC(多版本并发控制)核心结构:隐藏字段:DB_TRX_ID(事务ID)、DB_ROLL_PTR(回滚指针)ReadView:包含m_ids(活跃事务列表)、min_trx_id、max_trx_id等工作流程:SELECT时通过ReadView判断数据版本可见性UPDATE/DELETE时创建新版本并更新回滚指针(2) 锁机制锁类型说明共享锁(S锁)允许其他事务读,阻止写排他锁(X锁)阻止其他事务读写意向锁表级锁,提高锁检查效率间隙锁锁定索引记录间隙,防止幻读临键锁记录锁+间隙锁组合四、事务实践与优化1. 事务最佳实践-- 1. 合理控制事务大小START TRANSACTION;-- 只包含必要的操作(避免百万级更新)UPDATE accounts SET balance = balance - 100 WHERE id = 1;UPDATE accounts SET balance = balance + 100 WHERE id = 2;COMMIT;-- 2. 避免长事务SET STATEMENT max_statement_time=1 FOR START TRANSACTION;-- 长时间运行的操作COMMIT;-- 3. 正确处理死锁START TRANSACTION;-- 按固定顺序访问表资源UPDATE table1 SET ... WHERE ...;UPDATE table2 SET ... WHERE ...;COMMIT;2. 事务监控与问题排查-- 查看当前运行的事务SELECT * FROM information_schema.INNODB_TRX;-- 查看锁等待情况SELECT * FROM performance_schema.events_waits_current WHERE EVENT_NAME LIKE '%lock%';-- 查看长事务(超过60秒)SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;3. 性能优化建议合理设置隔离级别:非必要不使用SERIALIZABLE控制事务粒度:避免包含过多SQL或大数据量操作索引优化:减少锁定的数据范围避免交叉访问:多事务按相同顺序访问资源使用乐观锁:对冲突少的场景使用版本号控制五、高级事务模式1. 分布式事务(XA)-- MySQL XA事务示例XA START 'transaction_id';UPDATE account SET balance = balance - 100 WHERE user_id = 1;XA END 'transaction_id';XA PREPARE 'transaction_id';XA COMMIT 'transaction_id';-- 或XA ROLLBACK 'transaction_id';2. 保存点(Savepoint)START TRANSACTION;INSERT INTO orders VALUES(...);SAVEPOINT sp1;UPDATE inventory SET ...;IF (error_condition) THEN ROLLBACK TO SAVEPOINT sp1; -- 回滚到sp1END IF;COMMIT;六、常见问题解答Q:为什么REPEATABLE READ能避免幻读?A:InnoDB通过间隙锁(Gap Lock)锁定索引记录间的间隙,阻止其他事务在范围内插入数据。例如:-- 事务ASELECT * FROM users WHERE age > 20 FOR UPDATE; -- 锁定(20,+∞)的间隙-- 事务B尝试插入age=25的记录会被阻塞INSERT INTO users (age) VALUES (25);Q:如何选择合适的事务隔离级别?A:金融系统:REPEATABLE READ(需要避免幻读)报表查询:READ COMMITTED(提高并发)数据迁移:READ UNCOMMITTED(仅临时使用)强一致性需求:SERIALIZABLE(性能代价高)Q:大事务有哪些危害?A:长时间持有锁,导致并发性能下降Undo Log膨胀,影响存储空间主从复制延迟崩溃恢复时间变长总结MySQL事务机制通过Undo Log、Redo Log、MVCC和锁等技术实现了ACID特性。合理使用事务需要:根据业务特点选择适当的隔离级别控制事务粒度和执行时间监控和优化锁竞争在分布式环境下考虑XA或其他分布式事务方案理解事务的底层实现原理,有助于开发高性能、高可用的数据库应用。
-
事务作为保障数据可靠性的核心机制,能够确保一系列数据库操作要么全部成功提交,要么全部失败回滚。本文我将从事务的基本操作入手,深入剖析事务的ACID特性、常见并发问题以及不同隔离级别,并结合丰富的示例和实战场景,帮你全面掌握MySQL事务的核心知识。一、事务概述1.1 什么是事务事务(Transaction)是数据库操作的最小逻辑单元,它由一个或多个数据库操作组成,这些操作被视为一个不可分割的整体。例如,在银行转账场景中,从账户A扣除金额和向账户B增加金额这两个操作必须作为一个事务执行,确保资金的转移过程完整且一致。1.2 事务的作用保证数据一致性:确保一组相关操作要么全部成功,要么全部失败,避免出现部分操作成功、部分失败导致的数据不一致问题。支持错误恢复:当事务执行过程中出现错误时,可以回滚到事务开始前的状态,防止错误数据被提交到数据库。处理并发访问:通过隔离级别控制多个事务并发执行时的相互影响,保证数据的正确性和完整性。二、MySQL事务基本操作2.1 开启事务在MySQL中,可以使用以下两种方式开启事务:显式开启:使用START TRANSACTION或BEGIN语句手动开启一个事务。START TRANSACTION;-- 或者BEGIN;隐式开启:在某些存储引擎(如InnoDB)中,当执行一个会修改数据的SQL语句(如INSERT、UPDATE、DELETE)时,若当前没有活跃事务,MySQL会自动开启一个事务。2.2 提交事务使用COMMIT语句提交事务,将事务中所有操作的结果永久保存到数据库。COMMIT;提交后,事务中对数据的修改将对其他事务可见。2.3 回滚事务使用ROLLBACK语句回滚事务,撤销事务中所有操作对数据的修改,将数据库恢复到事务开始前的状态。ROLLBACK;当事务执行过程中出现错误或不满足业务条件时,通常会执行回滚操作。2.4 保存点(SAVEPOINT)保存点用于在事务中创建一个标记点,可以在需要时回滚到特定的保存点,而不是整个事务。创建保存点:使用SAVEPOINT语句创建保存点。SAVEPOINT savepoint_name;回滚到保存点:使用ROLLBACK TO SAVEPOINT语句回滚到指定的保存点。ROLLBACK TO SAVEPOINT savepoint_name;释放保存点:使用RELEASE SAVEPOINT语句删除保存点。RELEASE SAVEPOINT savepoint_name;AI写代码sql1示例:START TRANSACTION;INSERT INTO users (username, password) VALUES ('user1', 'pass1');SAVEPOINT insert_user1;UPDATE users SET password = 'new_pass1' WHERE username = 'user1';-- 发现更新操作有误,回滚到插入用户的状态ROLLBACK TO SAVEPOINT insert_user1;COMMIT;三、事务的ACID特性3.1 原子性(Atomicity)原子性要求事务中的所有操作要么全部成功执行,要么全部失败回滚,不存在部分成功的情况。就像银行转账,扣款和入账必须同时完成,否则就都不执行,保证资金的完整性。3.2 一致性(Consistency)一致性确保事务执行前后,数据库的状态始终符合预定的业务规则。例如,在转账事务中,转账前后两个账户的总金额应该保持不变,不会因为事务执行出现金额丢失或增加的情况。3.3 隔离性(Isolation)隔离性定义了多个事务并发执行时,一个事务对其他事务的影响程度。不同的隔离级别决定了事务之间可见性和干扰程度的差异,后面将详细介绍。3.4 持久性(Durability)持久性保证一旦事务提交成功,其对数据库的修改将永久保存,即使系统发生故障(如断电、崩溃),数据也不会丢失。InnoDB存储引擎通过事务日志(重做日志)来实现持久性。四、事务并发问题在多用户并发访问数据库时,若不进行有效的控制,事务之间可能会产生以下问题:4.1 脏读(Dirty Read)一个事务读取到另一个未提交事务修改的数据。例如,事务A修改了账户余额,但未提交,此时事务B读取了这个未提交的余额数据,若事务A随后回滚,事务B读取的数据就是无效的,即脏数据。4.2 不可重复读(Non-repeatable Read)在同一个事务中,多次读取同一数据时结果不一致。例如,事务A先读取了某条订单记录,之后事务B修改并提交了这条记录,事务A再次读取时得到的是修改后的数据,导致在一个事务内读取结果不统一。4.3 幻读(Phantom Read)一个事务在执行过程中,另一个事务插入了新的数据,导致第一个事务再次查询时出现了之前没有的数据,就像产生了“幻觉”。例如,事务A查询符合条件的订单列表,事务B在此时插入了一条符合条件的新订单并提交,事务A再次查询时会发现多出了一条记录。4.4 丢失更新(Lost Update)两个事务同时读取同一数据并进行更新,后提交的事务会覆盖先提交事务的更新结果,导致先提交事务的更新丢失。五、事务隔离级别为了解决并发问题,MySQL提供了四种事务隔离级别,每种级别对并发事务的隔离程度不同,从低到高分别是:5.1 读未提交(Read Uncommitted)这是最低的隔离级别,允许一个事务读取另一个未提交事务修改的数据,会导致脏读、不可重复读和幻读问题。一般很少在实际应用中使用。SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;5.2 读已提交(Read Committed)一个事务只能读取另一个已提交事务修改的数据,可以避免脏读,但仍然存在不可重复读和幻读问题。这是Oracle数据库的默认隔离级别,也是MySQL中InnoDB和MyISAM存储引擎的默认隔离级别(在MySQL 8.0之前,InnoDB默认隔离级别为REPEATABLE READ)。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;5.3 可重复读(Repeatedly Read)在同一个事务中,多次读取同一数据时结果保持一致,解决了脏读和不可重复读问题,但无法完全避免幻读。这是MySQL 8.0之前InnoDB存储引擎的默认隔离级别。通过MVCC(多版本并发控制)机制,InnoDB在可重复读级别下能在一定程度上解决幻读问题。SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;5.4 串行化(Serializable)这是最高的隔离级别,通过强制事务串行执行,避免了所有并发问题(脏读、不可重复读、幻读),但会严重影响系统性能,因为事务只能一个接一个执行,降低了并发处理能力。SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;六、不同隔离级别对比与选择隔离级别 脏读 不可重复读 幻读 并发性能 适用场景读未提交 是 是 是 高 对数据一致性要求极低的场景读已提交 否 是 是 较高 大多数OLTP应用场景可重复读 否 否 部分解决 中 对数据一致性要求较高的场景串行化 否 否 否 低 对数据一致性要求极高的场景在实际应用中,需要根据业务对数据一致性和并发性能的需求来选择合适的隔离级别。一般情况下,读已提交和可重复读是比较常用的隔离级别。七、事务与存储引擎MySQL支持多种存储引擎,不同存储引擎对事务的支持程度不同:InnoDB:支持事务,完全满足ACID特性,是最常用的支持事务的存储引擎,适用于对数据一致性要求高的应用场景,如电商交易、金融系统等。MyISAM:不支持事务,也不支持外键约束,适合用于只读或读多写少的场景,如博客系统、数据仓库等。Memory:不支持事务,数据存储在内存中,读写速度快,但数据在服务器重启后会丢失,常用于临时数据存储。八、事务最佳实践8.1 事务范围控制尽量缩短事务的执行时间,避免长时间占用数据库资源,影响其他事务的执行。只将必要的操作包含在事务中,减少事务的复杂性和潜在风险。8.2 错误处理在应用程序中捕获数据库操作异常,并及时回滚事务,防止错误数据提交。记录详细的错误日志,便于排查问题。8.3 性能优化合理选择事务隔离级别,在保证数据一致性的前提下,尽可能提高并发性能。避免在事务中执行大量复杂的查询操作,将查询操作移出事务或进行优化。———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/aa_hdkf_vg/article/details/148801487
-
一、基础查询语句1. 简单查询-- 查询表中所有数据SELECT * FROM 表名;-- 查询特定列SELECT 列1, 列2, 列3 FROM 表名;-- 带条件的查询SELECT * FROM 表名 WHERE 条件;2. 条件查询-- 比较运算符SELECT * FROM products WHERE price > 100;-- 逻辑运算符SELECT * FROM employees WHERE salary > 5000 AND department = 'IT';-- IN 操作符SELECT * FROM customers WHERE country IN ('USA', 'UK', 'Canada');-- BETWEEN 操作符SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';-- LIKE 模糊查询SELECT * FROM products WHERE product_name LIKE '%手机%';3. 排序和限制-- 排序查询SELECT * FROM employees ORDER BY salary DESC;-- 多列排序SELECT * FROM students ORDER BY grade DESC, name ASC;-- 限制返回行数SELECT * FROM products LIMIT 10;-- 分页查询SELECT * FROM orders LIMIT 10 OFFSET 20; -- 第3页,每页10条二、高级查询语句1. 聚合函数-- 计数SELECT COUNT(*) FROM customers;-- 求和SELECT SUM(sales) FROM orders WHERE year = 2023;-- 平均值SELECT AVG(salary) FROM employees;-- 最大值/最小值SELECT MAX(price), MIN(price) FROM products;-- 分组统计SELECT department, COUNT(*) as employee_count FROM employees GROUP BY department;2. 连接查询-- 内连接SELECT o.order_id, c.customer_nameFROM orders oJOIN customers c ON o.customer_id = c.customer_id;-- 左连接SELECT e.employee_name, d.department_nameFROM employees eLEFT JOIN departments d ON e.department_id = d.department_id;-- 右连接SELECT p.product_name, c.category_nameFROM products pRIGHT JOIN categories c ON p.category_id = c.category_id;-- 全外连接(MySQL通过UNION实现)SELECT e.employee_name, d.department_nameFROM employees eLEFT JOIN departments d ON e.department_id = d.department_idUNIONSELECT e.employee_name, d.department_nameFROM employees eRIGHT JOIN departments d ON e.department_id = d.department_idWHERE e.employee_id IS NULL;3. 子查询-- WHERE子句中的子查询SELECT * FROM products WHERE price > (SELECT AVG(price) FROM products);-- FROM子句中的子查询SELECT dept_avg.department, dept_avg.avg_salaryFROM ( SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department) AS dept_avgWHERE dept_avg.avg_salary > 5000;-- IN子查询SELECT * FROM customersWHERE customer_id IN ( SELECT customer_id FROM orders WHERE order_date > '2023-01-01');三、数据操作语句1. 插入数据-- 插入单行INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2);-- 插入多行INSERT INTO products (product_name, price)VALUES ('手机', 2999), ('电脑', 5999), ('平板', 1999);-- 从其他表插入数据INSERT INTO new_employees (name, salary)SELECT employee_name, salary FROM temp_employees;2. 更新数据-- 简单更新UPDATE products SET price = 3499 WHERE product_id = 101;-- 多列更新UPDATE employeesSET salary = salary * 1.1, bonus = bonus + 500WHERE department = '研发部';-- 使用子查询更新UPDATE ordersSET status = '已完成'WHERE order_id IN ( SELECT order_id FROM payments WHERE payment_status = '已支付');3. 删除数据-- 删除指定数据DELETE FROM customers WHERE customer_id = 1001;-- 删除所有数据(慎用)DELETE FROM temp_logs;-- 使用子查询删除DELETE FROM productsWHERE product_id NOT IN ( SELECT product_id FROM order_items);四、表操作语句1. 创建表CREATE TABLE employees ( employee_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE, salary DECIMAL(10,2) DEFAULT 0, hire_date DATE, department_id INT, FOREIGN KEY (department_id) REFERENCES departments(department_id));2. 修改表结构-- 添加列ALTER TABLE employees ADD COLUMN phone VARCHAR(20);-- 修改列ALTER TABLE employees MODIFY COLUMN phone VARCHAR(15);-- 删除列ALTER TABLE employees DROP COLUMN phone;-- 添加索引ALTER TABLE products ADD INDEX idx_product_name (product_name);-- 添加外键ALTER TABLE ordersADD CONSTRAINT fk_customerFOREIGN KEY (customer_id) REFERENCES customers(customer_id);五、高级特性1. 视图-- 创建视图CREATE VIEW high_value_customers ASSELECT customer_id, name, SUM(order_total) as total_spentFROM customers cJOIN orders o ON c.customer_id = o.customer_idGROUP BY customer_id, nameHAVING SUM(order_total) > 10000;-- 使用视图SELECT * FROM high_value_customersORDER BY total_spent DESC;2. 存储过程DELIMITER //CREATE PROCEDURE update_salary(IN dept_id INT, IN increase_percent DECIMAL(5,2))BEGIN UPDATE employees SET salary = salary * (1 + increase_percent/100) WHERE department_id = dept_id;END //DELIMITER ;-- 调用存储过程CALL update_salary(5, 10); -- 部门ID为5的员工加薪10%3. 事务处理START TRANSACTION;UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1;UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2;-- 如果一切正常COMMIT;-- 如果出错ROLLBACK;六、性能优化技巧1. 使用EXPLAIN分析查询EXPLAIN SELECT * FROM orders WHERE customer_id = 1001;2. 索引优化-- 添加复合索引ALTER TABLE orders ADD INDEX idx_customer_date (customer_id, order_date);-- 强制使用索引SELECT * FROM orders FORCE INDEX (idx_customer_date)WHERE customer_id = 1001 AND order_date > '2023-01-01';3. 查询重写优化-- 避免SELECT *SELECT customer_id, name, email FROM customers;-- 使用JOIN代替子查询SELECT c.customer_id, c.nameFROM customers cJOIN orders o ON c.customer_id = o.customer_idWHERE o.order_date > '2023-01-01';以上SQL语句涵盖了MySQL日常开发中的大多数场景,您可以根据具体需求进行调整和组合使用。
-
MySQL 主备切换教程:从手动到自动的实战指南在数据库的高可用架构中,MySQL 主备模式是保障数据安全和业务连续性的重要方案。当主数据库出现故障,如硬件损坏、软件崩溃或人为误操作时,及时进行主备切换,将备库提升为主库,能最大限度减少业务中断时间。本文将详细介绍 MySQL 主备切换的完整流程,涵盖手动切换与自动切换两种方式,帮助你在实际场景中快速应对突发状况。一、主备切换前的准备工作1.1 确认主备环境状态在进行主备切换前,务必确保主库和备库的数据同步正常。通过在备库执行SHOW SLAVE STATUS\G命令,查看Slave_IO_Running和Slave_SQL_Running状态是否均为Yes,这表明备库的 I/O 线程和 SQL 线程都在正常工作,数据同步无异常。同时,记录下备库的Exec_Master_Log_Pos值,该值表示备库已经执行到主库二进制日志的位置,后续切换时会用到。1.2 备份数据虽然主备切换是为了保障业务连续性,但为防止意外情况导致数据丢失,在切换前对主库和备库的数据进行一次全量备份是十分必要的。可以使用mysqldump命令进行备份,例如:mysqldump -u [username] -p [database_name] > backup_file.sql执行命令后,按照提示输入密码,即可将指定数据库备份到backup_file.sql文件中。1.3 通知相关业务方主备切换过程中可能会短暂中断数据库服务,因此需要提前通知相关业务团队,让其做好服务降级、缓存预热等准备工作,将对业务的影响降到最低。二、手动主备切换2.1 停止主库写入操作在主库上执行FLUSH TABLES WITH READ LOCK;命令,该命令会锁定所有表,阻止新的写入操作,确保数据的一致性。此时,主库处于只读状态,所有写入请求将被阻塞。2.2 记录主库二进制日志信息在主库锁定表后,执行SHOW MASTER STATUS\G命令,记录下File和Position的值,这两个值分别表示当前主库二进制日志文件名和位置,后续在备库提升为主库时需要用到。2.3 停止备库复制在备库上执行STOP SLAVE;命令,停止备库的 I/O 线程和 SQL 线程,暂停数据同步。2.4 配置备库为主库在备库上执行以下命令,将备库提升为主库:RESET MASTER; CHANGE MASTER TO MASTER_HOST = 'localhost', MASTER_USER = 'your_master_user', MASTER_PASSWORD = 'your_master_password', MASTER_LOG_FILE = '记录的主库File值', MASTER_LOG_POS = 记录的主库Position值; START SLAVE; 上述命令中,RESET MASTER会清除备库原有的复制信息,CHANGE MASTER TO重新配置主库连接信息,START SLAVE启动复制功能。此时,备库已经切换为主库,可以接收新的写入请求。2.5 解除主库锁定在原主库上执行UNLOCK TABLES;命令,解除表锁定,将其作为新的备库。然后在原主库上执行CHANGE MASTER TO命令,配置连接到新主库的信息,并启动复制:CHANGE MASTER TO MASTER_HOST = '新主库IP地址', MASTER_USER = '新主库用户名', MASTER_PASSWORD = '新主库密码', MASTER_LOG_FILE = '新主库的File值', MASTER_LOG_POS = '新主库的Position值'; START SLAVE; 至此,手动主备切换完成。三、自动主备切换自动主备切换通常借助工具实现,常见的有 MHA(Master High Availability)和 Orchestrator。下面以 MHA 为例,介绍自动主备切换的实现步骤。3.1 安装 MHA在所有数据库节点和管理节点上安装 MHA 相关软件包,包括mha4mysql-manager和mha4mysql-node。以 CentOS 系统为例,可以使用以下命令安装:yum install mha4mysql-manager mha4mysql-node3.2 配置 MHA在管理节点上创建 MHA 配置文件,如masterha.cnf,配置内容如下:[server default] manager_workdir=/var/log/mha manager_log=/var/log/mha/manager.log master_binlog_dir=/var/lib/mysql master_ip_failover_script=/path/to/failover_script ssh_user=root user=root password=your_password ping_interval=1 [server1] hostname=主库IP地址 port=3306 [server2] hostname=备库IP地址 port=3306 上述配置文件中,master_ip_failover_script指定了主库切换时的 IP 漂移脚本,该脚本会将原主库的 IP 地址切换到新主库上。3.3 启动 MHA在管理节点上执行masterha_manager --conf=/path/to/masterha.cnf命令启动 MHA 服务。MHA 会自动监控主库状态,当检测到主库故障时,会自动执行主备切换操作,将备库提升为主库,并将原主库配置为新的备库。四、主备切换后的检查与验证4.1 检查新主库状态在新主库上执行SHOW MASTER STATUS\G命令,确认其是否处于主库状态,以及二进制日志信息是否正常。同时,尝试进行数据写入操作,验证新主库是否可以正常接收和处理写入请求。4.2 检查新备库状态在新备库上执行SHOW SLAVE STATUS\G命令,确保Slave_IO_Running和Slave_SQL_Running状态均为Yes,数据同步正常。通过查询数据,验证新备库的数据是否与新主库一致。4.3 通知业务方恢复服务在确认主备切换成功且数据库状态正常后,通知相关业务团队恢复业务服务,监控业务运行情况,确保系统正常运转。五、常见问题与解决方法5.1 数据同步延迟在主备切换前,如果备库存在数据同步延迟,可能会导致切换后数据不一致。可以通过优化主库性能、增加备库资源、调整复制参数等方式减少延迟。同时,在切换前等待数据同步完成,确保备库与主库数据一致。5.2 切换后连接异常如果切换后主备库之间的连接出现异常,检查CHANGE MASTER TO命令中的配置参数是否正确,包括 IP 地址、端口号、用户名、密码以及二进制日志信息等。确保主备库之间的网络连通性正常,防火墙规则允许数据库端口通信。5.3 MHA 切换失败如果使用 MHA 进行自动主备切换失败,查看 MHA 的日志文件/var/log/mha/manager.log,分析失败原因。常见原因包括配置错误、IP 漂移脚本执行失败、SSH 连接问题等。根据日志提示,修正相应的配置或脚本,重新启动 MHA 服务进行切换。以上全面讲解了 MySQL 主备切换流程。若你在实际操作中遇到特殊情况,或想了解更多数据库优化技巧,欢迎随时和我分享。
-
Redis 作为缓存层,MySQL 作为存储层,两者数据一致性问题是分布式系统中的常见挑战。以下从不一致原因、解决方案、适用场景三方面详细分析,并提供实践建议。一、数据不一致的核心原因缓存更新策略问题先更新数据库,再更新缓存并发场景下可能导致缓存与数据库数据不一致。示例:线程 A 更新数据库字段 count=10。线程 B 读取缓存(旧值 count=5)并完成业务逻辑。线程 A 更新缓存为 count=10。最终缓存与数据库一致,但线程 B 读取到了旧值。先更新缓存,再更新数据库数据库更新失败时,缓存与数据库数据不一致。示例:线程 A 更新缓存为 count=10。数据库更新操作因网络问题失败,缓存为新值,数据库为旧值。缓存穿透、击穿、雪崩缓存穿透:大量请求访问不存在的数据,直接击穿缓存到数据库,导致数据库压力陡增,可能因脏数据更新缓存引发不一致。缓存击穿:热点数据过期瞬间,大量请求同时访问数据库,可能因更新顺序问题导致缓存与数据库不一致。缓存雪崩:大量缓存集中过期,请求涌入数据库,若数据库更新不及时,缓存重建后可能携带旧数据。异步更新与延迟问题异步队列(如 Kafka)处理缓存更新时,若队列积压或消费失败,会导致缓存更新延迟,引发数据不一致。二、解决方案:保证数据最终一致性缓存更新策略优化策略 实现逻辑 适用场景 优缺点Cache-Aside(旁路缓存) 读操作:先查缓存,命中则返回未命中则查数据库,更新缓存写操作:先更新数据库,再删除缓存 读多写少场景(如商品详情页) - 优点:逻辑简单,避免脏数据缺点:删除缓存后首次读会穿透到数据库Write-Through(写穿) 写操作时同时更新数据库和缓存,两者都成功才算操作完成 对一致性要求极高的场景 - 优点:强一致性缺点:性能较低(两次写操作)Write-Behind(写回) 写操作时先更新缓存,再通过异步任务批量更新数据库(类似 Linux 磁盘缓存机制) 写多读少场景(如日志系统) - 优点:高性能缺点:异步任务失败会导致数据丢失Delete Cache(删除缓存) 写操作时先更新数据库,再删除缓存(主流方案,需结合重试或消息队列) 大多数读写混合场景 - 优点:避免缓存与数据库双写不一致缺点:需处理缓存击穿问题推荐方案:读多写少场景:采用 Cache-Aside + 删除缓存,写操作后删除缓存,读操作时自动重建缓存。写多读少场景:采用 Write-Behind + 异步重试,通过队列保证数据库最终更新。解决缓存穿透、击穿、雪崩缓存穿透:对不存在的数据,缓存一个特殊值(如 null)并设置短过期时间(如 5 分钟),避免重复查询数据库。使用布隆过滤器(Bloom Filter)提前过滤无效请求。缓存击穿:对热点数据设置互斥锁(如 Redis 的 setnx),确保同一时间只有一个线程重建缓存。延长热点数据过期时间,或采用逻辑过期(在缓存值中存储过期时间,业务层判断是否需要异步更新)。缓存雪崩:给缓存过期时间添加随机抖动(如 TTL=300s±30s),避免集中过期。启用 Redis 集群的主从复制和哨兵机制,保障缓存层高可用。对核心业务添加熔断机制(如 Hystrix),防止数据库被压垮。异步更新与补偿机制消息队列异步更新缓存:写操作时,先更新数据库,再向消息队列(如 Kafka、RabbitMQ)发送一条更新缓存的消息,消费者监听队列并执行缓存删除或更新操作。示例流程:是否更新 MySQL成功?发送消息到队列返回失败消费者消费消息,删除 Redis 缓存重试与死信队列:若缓存更新失败,将消息放入重试队列(如延迟队列),多次重试后仍失败则放入死信队列,人工处理。定期扫描数据库 binlog(如使用 Canal),对比缓存数据,自动补偿不一致的记录。4. 读写分离场景的一致性优化主从数据库延迟可能导致从库读到旧数据,进而更新缓存为旧值。解决方案:写操作后强制读主库(如通过业务逻辑判断,写操作后 5 秒内读主库)。使用数据库中间件(如 MyCat)实现读写分离,并提供强制读主库的接口。三、一致性级别与适用场景一致性级别 实现方式 典型场景强一致性 Write-Through(同步更新数据库和缓存) 金融交易、库存扣减最终一致性 Cache-Aside + 消息队列异步更新 + 重试机制 商品详情页、用户信息展示弱一致性 仅删除缓存,依赖读操作重建(允许短时间不一致) 首页推荐、实时统计(如点赞数)四、实践建议优先保证数据库一致性:缓存是提升性能的手段,而非数据存储核心。所有写操作必须以数据库成功为前提,缓存可通过补偿机制最终修正。监控与报警:监控缓存命中率、数据库慢查询、队列积压量等指标。配置报警规则,如缓存与数据库不一致率超过阈值时触发告警。定期全量同步:每天凌晨低谷期,通过定时任务全量扫描数据库,重建缓存(如使用 Redis Pipeline 批量写入),确保冷数据一致性。分场景设计:对一致性要求高的核心数据(如订单状态),采用同步更新策略或分布式事务(如 TCC 模式)。对非核心数据(如用户积分显示),允许秒级不一致,通过异步机制补偿。五、总结Redis 与 MySQL 的数据一致性是最终一致性问题,无法在所有场景下做到强一致。解决方案需结合业务需求,在性能与一致性间权衡:读多写少:优先使用 Cache-Aside + 删除缓存 + 异步重试。写多读少:考虑 Write-Behind + 批量异步更新,或引入搜索中间件(如 Elasticsearch)分担压力。高一致性场景:避免过度依赖缓存,直接操作数据库或使用专业分布式事务框架(如 Seata)。通过合理的缓存策略、补偿机制和监控体系,可将不一致性控制在业务可接受的范围内。
-
整理了下MySQL查询语句的执行顺序。(1) FROM(2) ON(3) JOIN(4) WHERE(5) GROUP BY(6) WITH (CUBE|ROLLUP)(7) HAVING(8) SELECT(9) DISTINCT(10) ORDER BY(11) LIMIT(1) FROM 子句 - 首先执行FROM employees eMySQL 会先读取 FROM 子句中的表信息(2) ON 条件 - 连接条件过滤JOIN departments d ON e.dept_id = d.id对连接表的行进行匹配只有满足 ON 条件的行才会被保留(3) JOIN 操作 - 执行表连接MySQL 支持多种连接方式:INNER JOIN、LEFT/RIGHT JOIN、CROSS JOIN(4) WHERE 条件 - 行级过滤WHERE e.salary > 5000 AND d.location = 'NY'此时不能使用 SELECT 中的别名不能使用聚合函数(如 COUNT, SUM 等)(5) GROUP BY - 分组操作GROUP BY d.name, e.position可以 GROUP BY 不在 SELECT 中的列分组后每组生成一行结果(6) WITH CUBE/ROLLUP - 生成超组GROUP BY d.name WITH ROLLUP生成小计和总计行(7) HAVING - 分组后过滤HAVING AVG(e.salary) > 6000可以使用聚合函数可以使用 SELECT 中的别名(8) SELECT - 选择输出列SELECT d.name, AVG(e.salary) as avg_sal计算表达式和函数调用定义列别名(9) DISTINCT - 去重操作SELECT DISTINCT departmentMySQL 可能在 GROUP BY 时就已经去重(10) ORDER BY - 结果排序ORDER BY avg_sal DESC可以使用 SELECT 中定义的别名对最终结果集排序,性能消耗较大(11) LIMIT - 结果限制LIMIT 10 OFFSET 5MySQL 特有语法,其他数据库可能用不同方式限制返回的行数转载自https://www.cnblogs.com/yanshajiuzhou/p/18903288
-
现在正值MySQL 30年庆典之际,MySQL布道师Frédéric Descamps 发表了一篇标题为MySQL InnoDB Data Recovery的演讲,基于对演讲内容的兴趣,做了相关测试,并制作视频,分享给大家cid:link_0
-
最近我零成本在本地搭了一个 SQL 智能体,不接入云、不付费、支持自然语言问答,简直是我日常开发提效的天花板。原来那些写 SQL 查业务数据、调接口前找字段、优化复杂 JOIN 的痛点,现在统统交给 AI 来搞定,精准又高效。全程本地运行,无需担心数据外泄,也不需要依赖第三方平台,更重要的是 —— 完全开源、零成本,硬核好玩!本篇文章就来分享我如何用最简单的方式,把自己的数据库“喂”给一个懂 SQL 的 AI,打造一个真正为开发者量身定制的“本地数据助理”。SQL 再也不是负担,而是乐趣。👨💻🚀what❓在平常的开发工作中,我们常常需要根据业务需求写各种 SQL 查询。尤其在面对复杂的数据库时,编写 SQL 语句时要查找表结构、字段类型、外键关系等,往往需要花费大量时间和精力。虽然 SQL 写得多了,但还是容易出错,特别是写复杂的联合查询(JOIN)和子查询时。再加上开发过程中需求变化频繁,修改 SQL 成了必不可少的工作。于是,我开始思考:有没有一种方式,可以让 AI 代替我写 SQL,自动理解我的需求并给出精准的查询语句?首先是基于安全,其次都是其次how❓经过一些调研和实验,我决定结合 Ollama + 阿里 Qwen2.5:7B 模型,以及 Anything LLM + nomic-embed-text 来搭建这个“SQL 智能体”。最酷的是:整个过程完全是本地化运行,不需要依赖云服务、无需付费、不会有数据泄露的风险。简直是开发者的福音!实现第一步:下载Ollama和所需大模型nomic-embed-text 是一个用于将文本数据嵌入到向量空间的工具,它可以将文本转化为向量表示。通过这种方式,你可以将自然语言文本转化为数值向量,以便进行计算和比较,常用于信息检索、文本相似度计算、聚类、分类等任务。根据你的电脑配置选择下载阿里的模型,当让这里你也可以选择别的模型,看自己需求。第二步:下载Anything LLM并配置首先配置为Ollama+自己所需大模型其次配置首选项第三步:新建工作区并投喂在完成以上步骤后,可以在Anything LLM中新建一个工作区,并投喂DDL信息,进行相关测试进行问答:
-
网上看到一个帖子说他们公司部署了一个基于AI去操作数据库的功能,然后用了10分钟后发现数据库被删了,大家觉得AI驱动数据库可取吗?
-
在MySQL中实现主备架构(主从复制)是提升数据库高可用性和读写分离能力的核心方案。以下是分步骤的完整实现指南,涵盖配置、验证、优化及故障处理:一、核心实现原理MySQL主备架构基于**二进制日志(Binary Log)**的异步/半同步复制机制:主库(Master):记录所有数据变更操作到二进制日志。从库(Slave):I/O线程:从主库拉取二进制日志并写入中继日志(Relay Log)。SQL线程:解析并执行中继日志中的SQL语句,实现数据同步。二、配置步骤(以MySQL 8.0为例)1. 前期准备角色IP地址关键配置项主库192.168.1.10server-id=1, log_bin=ON从库192.168.1.11server-id=2, read_only=ON2. 主库配置修改配置文件 /etc/my.cnf:[mysqld] server-id = 1 # 唯一ID,主从不能重复 log_bin = mysql-bin # 启用二进制日志 binlog_format = ROW # 推荐使用ROW格式(数据一致性最佳) expire_logs_days = 7 # 日志保留7天 sync_binlog = 1 # 每次事务提交都同步到磁盘(可选,影响性能)创建复制专用用户:CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'SecurePass123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES; 获取二进制日志位置(后续从库配置需用到):SHOW MASTER STATUS; -- 输出示例: -- +------------------+----------+ -- | File | Position | -- +------------------+----------+ -- | mysql-bin.000003 | 154 | -- +------------------+----------+ 3. 从库配置修改配置文件 /etc/my.cnf:[mysqld] server-id = 2 # 唯一ID relay_log = mysql-relay-bin # 中继日志路径 read_only = 1 # 设置为只读(防止误操作) log_slave_updates = 1 # 级联复制时需要(可选)配置复制关系:STOP SLAVE; -- 确保从库处于停止状态 CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='SecurePass123!', MASTER_LOG_FILE='mysql-bin.000003', -- 主库SHOW MASTER STATUS输出的File MASTER_LOG_POS=154; -- 主库SHOW MASTER STATUS输出的Position START SLAVE; 验证复制状态:SHOW SLAVE STATUS\G -- 关键指标: -- Slave_IO_Running: Yes # I/O线程状态 -- Slave_SQL_Running: Yes # SQL线程状态 -- Seconds_Behind_Master: 0 # 延迟(0表示实时同步) 三、生产环境优化建议1. 半同步复制(提升数据安全性)主库配置:[mysqld] rpl_semi_sync_master_enabled = 1 rpl_semi_sync_master_timeout = 1000 # 毫秒,超时后自动降级为异步复制从库配置:[mysqld] rpl_semi_sync_slave_enabled = 1 2. 多线程复制(提升从库性能)[mysqld] slave_parallel_workers = 4 # 根据CPU核心数调整 slave_parallel_type = LOGICAL_CLOCK # 基于组提交的多线程复制(MySQL 5.7+)3. GTID复制(简化复制管理)主库配置:[mysqld] gtid_mode = ON enforce_gtid_consistency = ON 从库配置:CHANGE MASTER TO MASTER_AUTO_POSITION = 1; -- 使用GTID自动定位 四、常见问题与解决方案问题现象可能原因解决方案Slave_IO_Running: No网络不通/权限不足检查防火墙、SELinux、用户权限Last_SQL_Error: Duplicate主键冲突跳过错误:SET GLOBAL sql_slave_skip_counter=1延迟持续增大从库负载过高优化查询、增加复制线程数复制中断主库二进制日志被清理重新配置复制(需主库保留足够日志)五、高可用架构扩展1. 监控脚本示例#!/bin/bash STATUS=$(mysql -uroot -pYourPass -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master") if echo "$STATUS" | grep -q "No"; then echo "ALERT: Replication failed!" | mail -s "MySQL Replication Alert" admin@example.com fi 2. 自动化故障切换(MHA方案)BinlogVIP FailoverReplicationReplicationMasterMHA ManagerCandidate MasterSlave1Slave2六、总结与最佳实践配置要点:确保server-id全局唯一。主从节点间网络畅通(10000/3306端口)。合理设置binlog_expire_logs_seconds(避免日志堆积)。生产环境建议:使用GTID模式简化管理。部署半同步复制防止数据丢失。监控Seconds_Behind_Master和复制错误。扩展方向:结合ProxySQL实现读写分离。使用Orchestrator实现自动化故障切换。通过以上步骤,MySQL主备架构能够为企业级应用提供可靠的数据冗余和故障恢复能力。根据实际业务需求,可进一步扩展为多主多从、级联复制等复杂拓扑。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签