面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

服务端阅读 05月27日 18:26

MariaDB 如何进行索引优化?有哪些索引类型和优化策略?

MariaDB 有哪些索引类型?各自的适用场景是什么?MariaDB 支持多种索引类型,理解它们的区别是做优化决策的基础。B-Tree 索引是 MariaDB 的默认索引结构,绝大多数场景下使用的都是它。B-Tree 采用平衡多路搜索树结构,叶子节点通过双向链表连接,天然支持等值查询、范围查询和排序操作。当你执行 WHERE id BETWEEN 100 AND 200 或 ORDER BY created_at DESC 时,B-Tree 可以高效地利用索引的有序性完成扫描,而不需要额外的文件排序(filesort)。哈希索引仅支持等值匹配查询,不支持范围查询和排序。它的查询时间复杂度接近 O(1),在精确查找场景下比 B-Tree 更快。MariaDB 中哈希索引主要用于 MEMORY 存储引擎的表,InnoDB 的自适应哈希索引(Adaptive Hash Index)是引擎内部自动维护的,不需要手动创建。面试中如果被问到"哈希索引为什么不能用于范围查询",核心原因是哈希值之间没有大小关系,无法利用有序性做区间扫描。全文索引(FULLTEXT)专门用于文本内容的模糊搜索,底层基于倒排索引实现。相比于 LIKE '%关键词%' 会导致全表扫描,全文索引可以快速定位包含目标词的记录。MariaDB 支持 MATCH ... AGAINST 语法,提供自然语言模式和布尔模式两种查询方式。需要注意的是,全文索引对中文分词的支持有限,通常需要借助 ngram 解析器或 Mroonga 引擎来处理中文场景。空间索引(SPATIAL)用于地理空间数据类型的索引,底层基于 R-Tree 结构。适合处理点、线、多边形等 GIS 数据的空间关系查询,比如"查找某坐标 5 公里范围内的门店"。空间索引仅支持 InnoDB 和 MyISAM 引擎,且索引列必须声明为 NOT NULL。聚簇索引不是一个独立的索引类型,而是 InnoDB 的数据组织方式。InnoDB 的主键索引就是聚簇索引——叶子节点直接存储完整的行数据,而非主键索引(二级索引)的叶子节点存储的是主键值。这意味着通过二级索引查找数据时,需要先查到主键值,再回表查询完整行数据,这个过程叫做"回表"。理解聚簇索引和回表机制,是掌握覆盖索引优化前提。创建索引时应该遵循哪些设计原则?索引不是越多越好。每多一个索引,INSERT/UPDATE/DELETE 就多一份维护成本,同时占用额外的磁盘空间。设计索引时需要把握几个关键原则。优先对高选择性列建索引。 选择性指的是列中不同值的数量与总行数的比值。选择性越高,索引过滤效果越好。例如用户表的 email 列选择性接近 1,几乎每条记录值都不同,索引过滤效率极高;而性别列只有两三个值,选择性极低,索引对查询的帮助微乎其微,优化器大概率会选择全表扫描。一个经验阈值是:当某值占比超过全表的 20% 时,优化器通常放弃使用索引。复合索引要遵循最左前缀原则。 对于索引 idx_abc(a, b, c),查询条件用到了 a、(a,b)、(a,b,c) 都能命中索引,但只用 b 或 c 则无法使用。实际设计中,应该把等值查询的列放在前面,范围查询的列放在后面。例如 WHERE status = 1 AND created_at > '2024-01-01',应建索引 (status, created_at) 而非 (created_at, status),因为等值过滤在前可以大幅缩小范围查询的扫描区间。利用覆盖索引减少回表。 如果查询需要的所有列都包含在索引中,InnoDB 直接从索引返回数据,无需回表读取行记录。例如 SELECT id, name FROM users WHERE name = 'John',如果 name 列上有索引且索引包含了 id(InnoDB 二级索引自动包含主键),这就是一次覆盖索引扫描。在 EXPLAIN 输出中,覆盖索引的 Extra 列会显示 Using index。避免在索引列上使用函数或表达式。 WHERE YEAR(created_at) = 2024 会导致索引失效,因为 MariaDB 需要对每一行计算函数值后才能比较。正确的写法是 WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01',这样优化器可以利用 B-Tree 的有序性做范围扫描。如何使用 EXPLAIN 分析查询的索引使用情况?EXPLAIN 是索引优化的核心工具,它展示优化器为查询选择的执行计划。EXPLAIN SELECT u.name, o.totalFROM users uJOIN orders o ON u.id = o.user_idWHERE u.status = 1 AND o.created_at > '2024-01-01';重点关注以下几个字段:type:访问类型,从好到差依次为 system > const > eq_ref > ref > range > index > ALL。出现 ALL 意味着全表扫描,需要重点优化。ref 表示使用索引等值匹配,range 表示索引范围扫描。key:实际使用的索引名称。如果显示 NULL,说明没有可用索引。rows:预估扫描行数。这个值越小越好,但它是基于统计信息的估算值,不一定精确。Extra:额外信息。Using index 表示覆盖索引,Using filesort 表示需要额外排序,Using temporary 表示使用了临时表,后两者通常意味着性能瓶颈。一个实用的工作流是:先跑 EXPLAIN 看执行计划,发现 type 为 ALL 或 rows 过大时,针对性地添加或调整索引,再反复验证。什么是索引失效?哪些常见写法会导致索引失效?索引失效指的是查询条件虽然涉及了索引列,但优化器最终选择不使用索引而做全表扫描。以下几种写法是常见的索引失效陷阱。对索引列使用函数或运算: WHERE name LIKE '%John'(左模糊)、WHERE YEAR(date_col) = 2024、WHERE id + 1 = 100,这些写法破坏了 B-Tree 的有序性,优化器无法利用索引定位。隐式类型转换: 当列是 VARCHAR 类型,查询条件写成 WHERE phone = 13800001111(数字类型),MariaDB 会将列值转为数字再做比较,这相当于对列施加了隐式函数,导致索引失效。正确写法是 WHERE phone = '13800001111'。OR 条件连接不同索引列: WHERE name = 'John' OR age = 25,如果 name 和 age 各有独立索引,MariaDB 在某些情况下可以使用 Index Merge 优化,但效果往往不如预期,不如改写为 UNION ALL 两个子查询。NOT IN、NOT EXISTS、!=、: 这些否定条件可能导致索引失效,尤其是结果集占比较大时。但并非绝对——如果否定条件过滤性很强(排除的值很少),优化器仍可能选择索引。索引列 IS NULL: 在 MariaDB 中,B-Tree 索引是包含 NULL 值的,WHERE col IS NULL 可以使用索引。这一点与 Oracle 等数据库不同,面试中注意区分。如何通过覆盖索引和索引下推提升查询性能?覆盖索引在前文已经提到,核心思路是让查询所需的所有列都在索引中,从而避免回表。实际应用中,可以通过 SELECT 指定列或将常用查询列加入复合索引来实现。-- 订单列表查询,只需要 id、status、created_atSELECT id, status, created_at FROM orders WHERE user_id = 100;-- 建立覆盖索引 (user_id, status, created_at)-- InnoDB 二级索引自动包含主键 id,因此这三列 + id 都在索引中ALTER TABLE orders ADD INDEX idx_user_status_created(user_id, status, created_at);索引下推(Index Condition Pushdown,ICP) 是 MariaDB 5.6+ 引入的优化。传统流程中,二级索引查到主键后必须回表才能判断 WHERE 中的其他条件;启用 ICP 后,存储引擎在索引扫描阶段就根据 WHERE 条件过滤,减少回表次数。-- 假设有索引 (last_name, first_name)SELECT * FROM users WHERE last_name = 'Smith' AND first_name LIKE '%ohn';-- 没有 ICP:先通过 last_name 索引查到所有 Smith 的主键,逐个回表再过滤 first_name-- 有 ICP:在索引扫描时直接对 first_name 做 LIKE 判断,不满足的跳过,减少回表在 EXPLAIN 的 Extra 列中,ICP 会显示 Using index condition。ICP 的适用条件是:查询使用了复合索引,且 WHERE 中有索引前列的等值条件加上后续列的条件过滤。如何监控和维护索引的健康状态?索引不是建完就一劳永逸的,随着数据增删改,索引可能出现碎片化、统计信息过期等问题,需要定期维护。-- 查看表的索引信息SHOW INDEX FROM users;-- 查看索引统计信息SELECT INDEX_NAME, SEQ_IN_INDEX, COLUMN_NAME, CARDINALITYFROM information_schema.STATISTICSWHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'users';-- 更新表的统计信息(不锁表)ANALYZE TABLE users;-- 重建表以消除碎片(会锁表)OPTIMIZE TABLE users;识别无用索引: 可以通过 sys.schema_unused_indexes 视图(MariaDB 10.6+)或开启 userstat 插件来追踪索引使用情况。长期未使用的索引应该清理,减少写入开销。监控索引碎片: 频繁的增删改会导致索引页出现空洞,降低索引扫描效率。OPTIMIZE TABLE 会重建表和索引,消除碎片,但操作期间会锁表,建议在低峰期执行。对于大表,可以考虑使用 ALTER TABLE ... ENGINE=InnoDB 的方式在线重建。统计信息维护: 优化器依赖统计信息(cardinality、rows 等)来选择执行计划。如果统计信息严重失真,可能导致优化器选错索引。定期执行 ANALYZE TABLE 可以刷新统计信息,且在 MariaDB 10.4+ 中该操作是在线进行的,不会阻塞读写。MariaDB 索引优化有哪些常见的实战案例?案例一:分页查询优化深分页是典型的性能杀手。SELECT * FROM orders ORDER BY id LIMIT 100000, 10 需要先扫描 100010 行再丢弃前 100000 行。-- 方案一:游标分页(推荐)-- 前端记录上一页最后一条的 id,下一页查询时带上SELECT * FROM orders WHERE id > 100000 ORDER BY id LIMIT 10;-- 方案二:延迟关联-- 先通过子查询在索引上定位 id,再回表取数据SELECT o.* FROM orders oJOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 10) tON o.id = t.id;案例二:多条件组合查询SELECT * FROM products WHERE category_id = 5 AND status = 1 AND price BETWEEN 100 AND 500 ORDER BY sales_count DESC LIMIT 20;索引设计:(category_id, status, sales_count)。前两列做等值过滤缩小范围,第三列利用索引有序性避免 filesort。price 列的范围查询放在最后处理。案例三:大表 JOIN 优化SELECT o.id, u.name FROM orders o JOIN users u ON o.user_id = u.idWHERE o.status = 2 AND u.region = 'CN';确保 JOIN 条件列(user_id、id)有索引,同时 orders 表在 status 上建索引、users 表在 region 上建索引,使驱动表的过滤结果尽可能小,减少循环 JOIN 的次数。掌握以上索引类型、设计原则、分析工具和实战技巧,基本能应对 MariaDB 索引优化的大部分面试问题和线上场景。核心思路始终是:用 EXPLAIN 验证,让索引覆盖查询,减少回表和全表扫描。
服务端阅读 05月27日 18:24

MariaDB 的 JSON 函数怎么用?有哪些常见坑?

MariaDB 从 10.2 开始提供了一套 JSON 函数,能直接在 SQL 里创建、查询、修改和校验 JSON 数据。JSON 列本质是 LONGTEXT 加 CHECK 约束,不是 MySQL 那种二进制格式,这一点在迁移时容易踩坑。追问JSONEXTRACT、JSONVALUE、JSON_QUERY 有什么区别?三个都是取值,但返回类型不同:| 函数 | 返回值 | 示例 ||------|--------|------|| JSONEXTRACT | 原始 JSON 片段(带引号) | "John" || JSONVALUE | 标量值(去引号) | John || JSON_QUERY | 对象或数组 | {"city":"NY"} |日常取字符串值用 -> 操作符(JSONEXTRACT 的语法糖),取标量用 JSONVALUE,取嵌套对象用 JSON_QUERY。JSONSET、JSONINSERT、JSON_REPLACE 有什么区别?JSON_SET:存在则更新,不存在则插入——万能选手JSON_INSERT:只在路径不存在时插入,已有值不动JSON_REPLACE:只在路径已存在时替换,没找到就跳过记住一句话:不确定用 SET,只想加新字段用 INSERT,只想改旧字段用 REPLACE。JSON 列怎么加索引?JSON 列不能直接建普通索引。两种方式:生成列 + 索引(推荐):ALTER TABLE products ADD COLUMN brand VARCHAR(50) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.brand'))) STORED, ADD INDEX idx_brand(brand);函数索引(MariaDB 10.3+):CREATE INDEX idx_brand ON products((CAST(attributes->'$.brand' AS CHAR(50))));MariaDB 的 JSON 和 MySQL 的 JSON 有什么区别?这是迁移时最容易翻车的地方:| 对比项 | MariaDB | MySQL ||--------|---------|-------|| 存储格式 | 原文 LONGTEXT | 二进制 JSON || JSON 类型 | LONGTEXT 的别名 | 独立数据类型 || 自动校验 | 需要 CHECK 约束 | 内置校验 || 部分更新 | 不支持 | 支持二进制增量更新 |MariaDB 存原文的好处是可以直接用文本函数处理,坏处是每次修改整个字段重写,大 JSON 字段更新性能差。用 JSON 列存数据有什么坑?没有 schema 约束:同列不同行结构可以完全不同,查出来才知道长什么样,排查问题靠蒙查询性能:每次取值都要解析 JSON,高频查询字段务必抽成普通列加索引更新代价:改一个字段整个 JSON 重写,大文档更新慢CHECK 约束别忘了加:CREATE TABLE products ( id INT PRIMARY KEY, attrs JSON, CONSTRAINT chk_json CHECK (JSON_VALID(attrs)));写段代码-- 建表 + 插入 + 查询一条龙CREATE TABLE products ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100), attrs JSON CHECK (JSON_VALID(attrs)));INSERT INTO products (name, attrs) VALUES ('Laptop', '{"brand":"Dell","ram":"16GB"}');-- 查品牌、改内存SELECT name, attrs->'$.brand' AS brand FROM products;UPDATE products SET attrs = JSON_SET(attrs, '$.ram', '32GB') WHERE id = 1;
服务端阅读 05月27日 17:38

如何优化MariaDB查询性能?

查询性能是数据库系统的生命线。一条低效的SQL可能拖垮整个应用,而一次精准的优化能让响应时间从秒级降到毫秒级。这篇文章从诊断、索引、写法、配置四个层面,给出经过生产验证的优化方法。用 EXPLAIN 定位性能瓶颈优化之前,先要找到问题。EXPLAIN 是最直接的诊断工具:EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';输出中有四个字段值得重点关注:type — 访问类型,从差到优依次为 ALL → index → range → ref → eq_ref → const。出现 ALL 意味着全表扫描,必须优化key — 实际使用的索引。如果为 NULL,说明索引未被命中rows — 预估扫描行数。数字越大,查询越慢Extra — Using filesort 表示额外排序,Using temporary 表示使用了临时表,两者都应尽量避免一个简单的判断标准:type 不是 ALL 且 Extra 没有 Using filesort/Using temporary,查询基本合格。索引:最有效的加速手段建立合适的复合索引单列索引在多条件查询时往往不够用。复合索引遵循最左前缀原则,把区分度高的列放前面:-- 假设查询条件为 WHERE user_id = ? AND status = ?-- user_id 区分度远高于 status,放前面CREATE INDEX idx_user_status ON orders(user_id, status);用覆盖索引避免回表当查询的列全部包含在索引中时,引擎无需回表读取数据行,性能提升显著:-- 索引 idx_user_status(user_id, status) 无法覆盖此查询(需要 amount 列)SELECT user_id, status, amount FROM orders WHERE user_id = 100;-- 建立覆盖索引后,直接从索引读取所有数据CREATE INDEX idx_user_status_amount ON orders(user_id, status, amount);避免索引失效的常见写法以下写法会导致索引无法命中:对索引列使用函数:WHERE YEAR(created_at) = 2025 改为 WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01'隐式类型转换:WHERE varchar_col = 123 改为 WHERE varchar_col = '123'前缀模糊查询:WHERE name LIKE '%John' 改为 WHERE name LIKE 'John%'使用 OR 连接不同索引列:改用 UNION ALL 拆分查询写法的优化技巧只查需要的列SELECT * 是性能杀手。它强制读取所有列的数据,增加 I/O 和内存开销,还可能破坏覆盖索引:-- 不推荐SELECT * FROM users WHERE id = 1;-- 推荐:只查业务需要的列SELECT id, name, email FROM users WHERE id = 1;用 JOIN 替代子查询MariaDB 优化器对子查询的处理不如 JOIN 高效,特别是 IN 子查询:-- 不推荐SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);-- 推荐SELECT u.id, u.name, u.email FROM users uINNER JOIN orders o ON u.id = o.user_idWHERE o.amount > 1000;UNION ALL 替代 UNIONUNION 会对结果去重,需要额外的排序操作。如果确定结果集无重复,用 UNION ALL 省掉去重开销:-- 不需要去重时SELECT name FROM customers WHERE region = 'east'UNION ALLSELECT name FROM suppliers WHERE region = 'east';深分页的两种优化方案OFFSET 值很大时,数据库需要扫描并跳过前面的所有行:-- 传统写法:跳过 10 万行,极其缓慢SELECT * FROM orders ORDER BY id LIMIT 100000, 10;-- 方案一:游标分页(要求排序字段连续且有索引)SELECT * FROM orders WHERE id > 100000 ORDER BY id LIMIT 10;-- 方案二:延迟关联(先查主键再回表,减少扫描列数)SELECT o.* FROM orders oINNER JOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 10) tmpON o.id = tmp.id;JOIN 优化被驱动表的连接列必须有索引小结果集驱动大表,减少循环次数当优化器选错连接顺序时,用 STRAIGHT_JOIN 强制指定:SELECT * FROM small_table sSTRAIGHT_JOIN large_table l ON s.id = l.small_id;配置层面的调优InnoDB 缓冲池这是影响 InnoDB 性能最重要的参数,建议设为物理内存的 50%-70%:innodb_buffer_pool_size = 4Ginnodb_buffer_pool_instances = 4排序和连接缓冲sort_buffer_size = 4M -- 每个连接的排序缓冲join_buffer_size = 4M -- 每个无索引连接的缓冲read_rnd_buffer_size = 4M -- MRR 读取缓冲临时表大小tmp_table_size = 256Mmax_heap_table_size = 256M超过此大小的临时表会写到磁盘,导致性能骤降。关于查询缓存注意:MariaDB 10.6 起默认禁用查询缓存,后续版本已移除该功能。如果使用 10.6+,不要配置 querycachesize,而是关注应用层缓存(如 Redis)。监控慢查询开启慢查询日志,定期分析并优化:SET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 1; -- 超过 1 秒记录SET GLOBAL log_queries_not_using_indexes = ON; -- 记录未使用索引的查询结合 pt-query-digest 工具分析慢查询日志,找出最需要优化的 SQL:pt-query-digest /var/lib/mysql/slow.log优化决策路径面对一个慢查询,按以下顺序排查:先用 EXPLAIN 查看执行计划,确认是否走了索引如果走了索引仍然慢,考虑建立覆盖索引或调整索引列顺序如果索引没有问题,检查查询写法是否有优化空间(避免 SELECT *、子查询改 JOIN、深分页优化)如果单条 SQL 已最优,考虑配置调优(缓冲池、排序缓冲、临时表大小)配置也调不动了,考虑架构层面优化(读写分离、分库分表、引入缓存)每个阶段都有明确的检查点和动作,避免盲目调参。
服务端阅读 05月27日 15:06

MariaDB 的事务隔离级别如何工作?怎样根据业务场景选择合适的隔离级别?

事务隔离级别要解决什么问题多个事务并发执行时,如果不加任何隔离措施,会出现三类数据不一致的问题:脏读(Dirty Read):事务 A 读到了事务 B 尚未提交的数据。如果事务 B 回滚,事务 A 拿到的就是根本不存在的"脏数据"。不可重复读(Non-Repeatable Read):事务 A 两次读取同一行数据,中间事务 B 修改并提交了这行,导致两次读到的值不同。幻读(Phantom Read):事务 A 两次执行相同的范围查询,中间事务 B 插入了新行并提交,导致第二次查询多出了"幻影行"。这三类问题逐层递进:脏读是读到了未提交的修改,不可重复读是已提交的修改导致同一行前后不一致,幻读是已提交的新增导致行数变化。SQL 标准据此定义了四种隔离级别,每种级别禁止一部分问题。四种隔离级别READ UNCOMMITTED(读未提交)最低隔离级别,允许事务读取其他事务未提交的修改。在这个级别下,脏读、不可重复读、幻读都可能发生。实际业务中几乎不会使用——读到未提交的数据意味着可能基于错误数据做出决策,风险极高。READ COMMITTED(读已提交)只允许读取已经提交的数据,杜绝了脏读。但同一事务内两次读取同一行,可能因为其他事务的提交而得到不同结果,所以不可重复读和幻读仍然存在。Oracle 和 PostgreSQL 默认使用这个级别。如果你的业务对同一事务内数据一致性要求不高(比如报表查询、大多数 Web 应用的读操作),READ COMMITTED 是一个性能和正确性的折中选择。REPEATABLE READ(可重复读)保证同一事务内多次读取同一行的结果一致,杜绝了脏读和不可重复读。按照 SQL 标准,幻读在这个级别仍然可能发生。但 MariaDB/MySQL 的 InnoDB 引擎通过 MVCC 和 Gap Lock 机制,在 REPEATABLE READ 下也避免了幻读——这比 SQL 标准更严格。MariaDB 和 MySQL 的默认隔离级别就是 REPEATABLE READ。大多数 OLTP 场景不需要改动它。SERIALIZABLE(串行化)最高隔离级别,所有事务按顺序串行执行,完全杜绝脏读、不可重复读和幻读。实现方式是对所有读取的行加共享锁,其他事务无法修改这些行直到锁释放。性能代价极大——并发度几乎归零。只在对数据一致性有极端要求的场景下使用,比如金融对账、审计等。隔离级别与并发问题的对应关系| 隔离级别 | 脏读 | 不可重复读 | 幻读 ||---|---|---|---|| READ UNCOMMITTED | 可能 | 可能 | 可能 || READ COMMITTED | 不会 | 可能 | 可能 || REPEATABLE READ | 不会 | 不会 | 可能(SQL 标准)/ 不会(MariaDB InnoDB) || SERIALIZABLE | 不会 | 不会 | 不会 |MVCC 是怎么工作的MVCC(Multi-Version Concurrency Control,多版本并发控制)是 InnoDB 实现 REPEATABLE READ 和 READ COMMITTED 的核心机制。它的基本思路是:每行数据保留多个版本,读操作访问的是某个历史快照,写操作创建新版本,读写互不阻塞。InnoDB 在每行记录后添加两个隐藏列:DBTRXID:最后修改该行的事务 ID。DBROLLPTR:回滚指针,指向 undo log 中该行的前一个版本。每个事务开始时会获得一个递增的事务 ID。读取数据时,InnoDB 根据当前事务 ID 和 undo log 链构建一个一致性视图(Read View),只返回对当前事务可见的版本。MVCC 在两个隔离级别下的行为差异:REPEATABLE READ:事务第一次读取时创建 Read View,整个事务期间复用同一个 View,所以同一行数据多次读取结果一致。READ COMMITTED:每次 SELECT 都创建新的 Read View,所以能看到其他事务已提交的最新数据。这就是为什么 READ COMMITTED 下会出现不可重复读,而 REPEATABLE READ 不会——Read View 的创建时机不同。Gap Lock 与 Next-Key LockMVCC 解决了快照读(普通 SELECT)的幻读问题,但当前读(SELECT … FOR UPDATE、UPDATE、DELETE 等加锁读)怎么办?InnoDB 的答案是 Gap Lock 和 Next-Key Lock。Record Lock:锁定索引上的单条记录。Gap Lock:锁定两条记录之间的间隙,阻止其他事务在该间隙中插入新行。Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一条记录及其前面的间隙。这是 InnoDB 在 REPEATABLE READ 下的默认加锁方式。举个例子:表中有 id = 1、5、10 三条记录。对 id = 5 加 Next-Key Lock 时,实际锁住的范围是 (1, 5],即 id 大于 1 且小于等于 5 的区间。其他事务无法在这个范围内插入新行(比如 id = 3),从而防止了幻读。在 READ COMMITTED 下,Gap Lock 被禁用(外键约束检查和唯一键冲突检查除外),只使用 Record Lock。这意味着其他事务可以在已锁定记录的间隙中自由插入,并发度更高,但可能出现幻读。InnoDB 与 MyISAM 的关键区别讨论事务隔离级别的前提是存储引擎支持事务。MariaDB 同时支持 InnoDB 和 MyISAM,但两者在事务能力上有本质区别:InnoDB:支持完整的 ACID 事务、行级锁、MVCC、外键约束和崩溃恢复。事务隔离级别的所有讨论都基于 InnoDB。MyISAM:不支持事务、不支持行级锁(只有表级锁)、没有 MVCC、没有崩溃恢复。在 MyISAM 表上执行 START TRANSACTION 不会有任何效果,ROLLBACK 也不会回滚任何修改。如果你的表使用 MyISAM 引擎,事务隔离级别的设置毫无意义。检查方法:SELECT ENGINE FROM information_schema.TABLESWHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';如果是 MyISAM,需要先转为 InnoDB:ALTER TABLE your_table ENGINE = InnoDB;MariaDB 5.5 起默认存储引擎已经是 InnoDB,新建的表无需额外指定。如何设置隔离级别查看当前隔离级别-- 查看全局默认隔离级别SELECT @@GLOBAL.transaction_isolation;-- 查看当前会话隔离级别SELECT @@SESSION.transaction_isolation;-- 兼容写法(MariaDB 中仍可用)SELECT @@tx_isolation;设置隔离级别-- 仅影响下一个事务SET TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 影响当前会话的所有后续事务SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 影响所有新会话的默认隔离级别(需要 SUPER 权限)SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;注意:事务已经开始后不能修改隔离级别,否则会报错 ERROR 1568 (25001): Transaction characteristics can't be changed while a transaction is in progress。在配置文件中设置在 my.cnf 中设置全局默认:[mysqld]transaction-isolation = READ-COMMITTED重启后生效。MariaDB 与 MySQL 的差异MariaDB 是 MySQL 的分支,事务隔离机制基本一致,但有几个值得注意的差异:txisolation vs transactionisolation:MySQL 8.0.3 移除了 tx_isolation 别名,只使用 transaction_isolation;MariaDB 两者都支持。WITH CONSISTENT SNAPSHOT:MariaDB 的 START TRANSACTION WITH CONSISTENT SNAPSHOT 兼容所有隔离级别,MySQL 8.0 前只支持 REPEATABLE READ。Gap Lock 行为:两者在 REPEATABLE READ 下的 Gap Lock 策略相同,但具体死锁场景可能因版本不同而有差异。默认二进制日志:MySQL 8.0 默认开启 binlog,MariaDB 默认关闭。binlog 的开启与否会影响事务的提交流程和性能。Aria 引擎:MariaDB 用 Aria 替代 MyISAM 作为非事务型引擎的选择,Aria 支持崩溃安全特性。怎么选择隔离级别选择隔离级别本质上是正确性和并发性能之间的权衡:大多数 Web 应用:保持默认的 REPEATABLE READ 即可。InnoDB 的 MVCC 让读操作不加锁,性能开销可控。高并发短事务场景(如秒杀、库存扣减):考虑降级到 READ COMMITTED。Gap Lock 在高并发下容易导致死锁,去掉 Gap Lock 可以减少锁冲突。代价是需要业务层处理不可重复读。报表和数据分析:READ COMMITTED 通常够用。报表查询对同一事务内的一致性要求不高,但需要看到最新提交的数据。金融对账和审计:SERIALIZABLE 或者在应用层加分布式锁。数据一致性优先,性能可以妥协。READ UNCOMMITTED:几乎没有任何合理的使用场景。即使你不在乎一致性,它也不会比 READ COMMITTED 快多少——InnoDB 在 RC 级别下读操作同样不加锁。一个常见的调优方向:把 REPEATABLE READ 降为 READ COMMITTED,减少 Gap Lock 带来的死锁问题。Drupal 官方就推荐使用 READ COMMITTED 替代默认的 REPEATABLE READ 来避免死锁。如果你的业务逻辑中大量使用范围查询和插入操作混合的场景,值得做这个调整。从性能角度看,隔离级别从低到高,锁持有时间递增、锁范围递增、并发度递减。REPEATABLE READ 的 Read View 在事务期间一直持有,长事务会占用大量 undo log 空间;READ COMMITTED 每次 SELECT 创建新 Read View,undo log 压力更小。所以控制事务长度比选择隔离级别本身更重要——无论用哪个级别,都应该让事务尽可能短。
服务端阅读 05月27日 10:48

MariaDB 窗口函数怎么用?排名、累计和同比计算详解

窗口函数是 SQL 里做数据分析最好用的工具——不用窗口函数,计算排名、累计、同比这些需求得写各种子查询和自连接,代码又长又慢。MariaDB 从 10.2 开始支持窗口函数,基本覆盖了 SQL 标准的核心功能。语法结构每个窗口函数都遵循同一套语法:函数名(表达式) OVER ( PARTITION BY 分组字段 ORDER BY 排序字段 ROWS/RANGE 窗口范围)OVER 子句定义了"窗口"——函数在这个范围内计算。PARTITION BY 把数据分组,每组独立计算;ORDER BY 决定组内排序;ROWS/RANGE 进一步约束参与计算的行范围。排名函数:ROWNUMBER、RANK、DENSERANK三个排名函数的区别在处理并列值时的行为:ROW_NUMBER:严格递增,1-2-3-4,不管值是否相同RANK:并列同名,跳号,1-1-3-4DENSE_RANK:并列同名,不跳号,1-1-2-3典型场景——每个部门薪资前三名:SELECT * FROM ( SELECT name, department, salary, DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk FROM employees) t WHERE rnk <= 3;用 DENSE_RANK 而不是 RANK,因为如果前三名有并列,RANK 会跳号,导致实际返回的记录少于 3 条。聚合函数做累计和移动平均窗口函数让 SUM/AVG/COUNT 不再只是"一组一个数",而是逐行累计:-- 累计销售额SELECT order_date, amount, SUM(amount) OVER (ORDER BY order_date) AS running_totalFROM orders;-- 7 天移动平均SELECT order_date, amount, AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_7dFROM orders;ROWS BETWEEN … AND … 定义了参与计算的行范围。6 PRECEDING AND CURRENT ROW 表示当前行和前 6 行,总共 7 行做平均。LAG 和 LEAD:访问前后行LAG 取前 N 行的值,LEAD 取后 N 行的值。算环比增长率靠它们:SELECT month, revenue, LAG(revenue, 1) OVER (ORDER BY month) AS prev_month, ROUND((revenue - LAG(revenue, 1) OVER (ORDER BY month)) / LAG(revenue, 1) OVER (ORDER BY month) * 100, 2) AS growth_pctFROM monthly_sales;LAG 的第二个参数是偏移量,第三个参数是默认值(缺省返回 NULL)。算同比就改成 LAG(revenue, 12),往前取 12 个月。FIRSTVALUE 和 LASTVALUE 的坑FIRSTVALUE 取分组内第一个值,LASTVALUE 取最后一个值。但 LAST_VALUE 有个常见陷阱——默认窗口范围是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,不是整个分区。所以如果你想取部门最低薪资,必须显式指定窗口范围:-- 正确写法:指定完整窗口范围SELECT name, department, salary, LAST_VALUE(salary) OVER ( PARTITION BY department ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS lowest_in_deptFROM employees;不加 ROWS BETWEEN … UNBOUNDED FOLLOWING,LAST_VALUE 每行返回的值都不一样——因为窗口只到当前行为止。ROWS 和 RANGE 的区别ROWS:按物理行号计算,窗口大小固定RANGE:按逻辑值范围计算,同一排序值的行作为一个整体-- ROWS:固定 3 行窗口SUM(amount) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)-- RANGE:同一天的行一起算SUM(amount) OVER (ORDER BY date RANGE BETWEEN INTERVAL 7 DAY PRECEDING AND CURRENT ROW)RANGE 适合按时间窗口聚合,同一时间点的所有行会被包含在同一个窗口内。ROWS 更精确,适合固定行数的滑动窗口。
服务端阅读 02月21日 15:51

MariaDB 性能调优有哪些关键参数和优化策略?

MariaDB 的性能调优需要从多个维度进行优化,以下是主要的调优策略:1. 配置参数优化# my.cnf 配置文件# 连接配置max_connections = 500max_connect_errors = 100000wait_timeout = 28800interactive_timeout = 28800# InnoDB 配置innodb_buffer_pool_size = 4Ginnodb_buffer_pool_instances = 4innodb_log_file_size = 512Minnodb_log_buffer_size = 16Minnodb_flush_log_at_trx_commit = 2innodb_flush_method = O_DIRECTinnodb_file_per_table = 1innodb_io_capacity = 2000innodb_io_capacity_max = 4000innodb_read_io_threads = 8innodb_write_io_threads = 8# MyISAM 配置key_buffer_size = 256Mmyisam_sort_buffer_size = 64M# 查询缓存(MariaDB 10.3+ 已移除)# query_cache_size = 64M# query_cache_type = 1# 临时表配置tmp_table_size = 256Mmax_heap_table_size = 256M# 排序和连接配置sort_buffer_size = 2Mread_buffer_size = 1Mread_rnd_buffer_size = 2Mjoin_buffer_size = 2M# 线程配置thread_cache_size = 16thread_stack = 256K# 日志配置slow_query_log = 1long_query_time = 2log_queries_not_using_indexes = 12. 内存优化-- 查看 InnoDB 缓冲池使用情况SHOW STATUS LIKE 'Innodb_buffer_pool%';-- 查看连接数SHOW STATUS LIKE 'Threads_connected';SHOW VARIABLES LIKE 'max_connections';-- 查看内存使用SHOW STATUS LIKE 'Memory%';3. 硬件优化CPU:多核处理器,建议 8 核以上内存:建议 16GB 以上,InnoDB 缓冲池占用 70-80%磁盘:使用 SSD,配置 RAID 10网络:千兆以上网络带宽4. 表结构优化-- 使用合适的数据类型-- 不推荐:VARCHAR(255) 用于状态字段-- 推荐:TINYINT 或 ENUM-- 规范化与反规范化权衡-- 读取频繁:适当反规范化-- 写入频繁:保持规范化-- 分区表ALTER TABLE orders PARTITION BY RANGE (YEAR(created_at)) ( PARTITION p2023 VALUES LESS THAN (2024), PARTITION p2024 VALUES LESS THAN (2025), PARTITION p2025 VALUES LESS THAN (2026));5. 查询优化-- 使用 EXPLAIN 分析查询EXPLAIN SELECT * FROM orders WHERE user_id = 1;-- 创建合适的索引CREATE INDEX idx_user_id_created ON orders(user_id, created_at);-- 避免全表扫描SELECT * FROM large_table WHERE indexed_column = 'value';-- 使用批量操作INSERT INTO users (name, email) VALUES ('John', 'john@example.com'), ('Jane', 'jane@example.com');6. 监控和诊断-- 查看慢查询SELECT * FROM mysql.slow_log ORDER BY query_time DESC LIMIT 10;-- 查看表状态SHOW TABLE STATUS FROM database_name;-- 查看索引使用情况SELECT * FROM information_schema.statistics WHERE table_schema = 'database_name';-- 查看进程列表SHOW PROCESSLIST;SHOW FULL PROCESSLIST;7. 性能测试工具# 使用 sysbench 进行性能测试sysbench oltp_read_write \ --mysql-host=localhost \ --mysql-port=3306 \ --mysql-user=root \ --mysql-password=password \ --mysql-db=test \ --tables=10 \ --table-size=100000 \ --threads=16 \ --time=300 \ --report-interval=10 \ run8. 定期维护-- 分析表ANALYZE TABLE table_name;-- 优化表OPTIMIZE TABLE table_name;-- 检查表CHECK TABLE table_name;-- 修复表REPAIR TABLE table_name;通过系统性的性能调优,可以显著提升 MariaDB 的整体性能和稳定性。
服务端阅读 02月21日 15:51

MariaDB 如何进行安全配置?有哪些安全最佳实践?

MariaDB 的安全配置是保护数据库安全的重要环节,以下是主要的安全配置措施:1. 用户权限管理-- 创建用户并设置密码CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';-- 授予最小必要权限GRANT SELECT, INSERT, UPDATE ON database_name.* TO 'app_user'@'localhost';-- 撤销权限REVOKE DELETE ON database_name.* FROM 'app_user'@'localhost';-- 删除用户DROP USER 'app_user'@'localhost';-- 查看用户权限SHOW GRANTS FOR 'app_user'@'localhost';-- 刷新权限FLUSH PRIVILEGES;2. 配置文件安全# my.cnf 安全配置# 禁止远程 root 登录skip-networking# 或bind-address = 127.0.0.1# 禁用本地文件加载local-infile = 0# 限制最大连接数max_connections = 100# 启用 SSLrequire-secure-transport = ONssl-ca = /path/to/ca-cert.pemssl-cert = /path/to/server-cert.pemssl-key = /path/to/server-key.pem# 设置默认认证插件default-authentication-plugin = mysql_native_password3. 密码策略-- 安装密码验证插件INSTALL PLUGIN simple_password_check SONAME 'simple_password_check.so';-- 配置密码策略SET GLOBAL simple_password_check_minimal_length = 12;SET GLOBAL simple_password_check_minimal_digit_count = 2;SET GLOBAL simple_password_check_minimal_special_char_count = 1;SET GLOBAL simple_password_check_minimal_uppercase_char_count = 1;-- 强制密码过期ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE;ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;4. 网络安全# 配置防火墙# 只允许特定 IP 访问iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 3306 -j ACCEPTiptables -A INPUT -p tcp --dport 3306 -j DROP# 使用 SSH 隧道ssh -L 3306:localhost:3306 user@remote_server5. 数据加密-- 启用 InnoDB 表加密-- my.cnf 配置innodb_encrypt_tables = ONinnodb_encrypt_log = ONinnodb_encryption_threads = 4innodb_encryption_rotate_key_age = 1-- 创建加密表CREATE TABLE sensitive_data ( id INT PRIMARY KEY, data VARCHAR(255), ENCRYPTION='Y') ENGINE=InnoDB ENCRYPTED=YES;-- 使用加密函数SELECT AES_ENCRYPT('sensitive_data', 'encryption_key');SELECT AES_DECRYPT(encrypted_data, 'encryption_key');6. 审计日志-- 启用审计日志-- my.cnf 配置plugin_load_add = server_auditserver_audit_events = CONNECT,QUERY,TABLEserver_audit_logging = ONserver_audit_file_path = /var/log/mariadb/audit.logserver_audit_file_rotate_size = 100Mserver_audit_file_rotations = 9-- 查看审计日志SELECT * FROM information_schema.server_audit;7. 定期安全检查-- 查看所有用户SELECT user, host FROM mysql.user;-- 查看空密码用户SELECT user, host FROM mysql.user WHERE authentication_string = '';-- 查看具有所有权限的用户SELECT user, host FROM mysql.user WHERE Grant_priv = 'Y';-- 查看匿名用户SELECT user, host FROM mysql.user WHERE user = '';8. 备份安全# 加密备份文件mysqldump -u root -p database_name | gzip | openssl enc -aes-256-cbc -salt -out backup.sql.gz.enc# 解密备份文件openssl enc -d -aes-256-cbc -in backup.sql.gz.enc | gunzip | mysql -u root -p database_name9. 安全最佳实践最小权限原则:只授予必要的权限定期更新:及时安装安全补丁强密码策略:使用复杂密码并定期更换网络隔离:限制数据库的网络访问加密传输:使用 SSL/TLS 加密连接审计监控:启用审计日志并定期审查备份保护:加密备份文件并安全存储定期检查:定期进行安全审计和漏洞扫描通过以上安全配置措施,可以显著提升 MariaDB 的安全性,保护数据免受未授权访问和攻击。
服务端阅读 02月21日 15:51

MariaDB 如何进行备份和恢复?有哪些备份策略和工具?

MariaDB 的备份与恢复是保障数据安全的重要环节,以下是主要的备份和恢复方法:1. 逻辑备份(mysqldump)全量备份:# 备份所有数据库mysqldump -u root -p --all-databases > all_databases.sql# 备份指定数据库mysqldump -u root -p database_name > database_name.sql# 备份指定表mysqldump -u root -p database_name table_name > table_name.sql# 备份并压缩mysqldump -u root -p database_name | gzip > database_name.sql.gz增量备份:# 启用二进制日志# my.cnf 配置log-bin = mysql-binbinlog-format = ROW# 备份二进制日志mysqlbinlog mysql-bin.000001 > binlog_backup.sql恢复数据:# 恢复完整备份mysql -u root -p < all_databases.sql# 恢复指定数据库mysql -u root -p database_name < database_name.sql# 恢复压缩备份gunzip < database_name.sql.gz | mysql -u root -p database_name# 应用二进制日志mysqlbinlog mysql-bin.000001 | mysql -u root -p2. 物理备份(Mariabackup)全量备份:# 创建备份mariabackup --backup --target-dir=/backup/full \ --user=root --password=password# 准备备份mariabackup --prepare --target-dir=/backup/full# 恢复备份mariabackup --copy-back --target-dir=/backup/full增量备份:# 创建全量备份mariabackup --backup --target-dir=/backup/full \ --user=root --password=password# 创建增量备份mariabackup --backup --target-dir=/backup/inc1 \ --incremental-basedir=/backup/full --user=root --password=password# 准备备份mariabackup --prepare --target-dir=/backup/fullmariabackup --prepare --target-dir=/backup/full \ --incremental-dir=/backup/inc13. 快照备份# 使用 LVM 快照lvcreate -L 10G -s -n mysql_snapshot /dev/vg0/mysqlmount /dev/vg0/mysql_snapshot /mnt/backuprsync -av /mnt/backup/ /backup/mysql/umount /mnt/backuplvremove /dev/vg0/mysql_snapshot4. 自动化备份脚本#!/bin/bash# backup.shDATE=$(date +%Y%m%d_%H%M%S)BACKUP_DIR="/backup/mariadb"MYSQL_USER="root"MYSQL_PASSWORD="password"# 创建备份目录mkdir -p $BACKUP_DIR# 全量备份mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD --all-databases \ --single-transaction --quick --lock-tables=false \ | gzip > $BACKUP_DIR/all_$DATE.sql.gz# 保留最近7天的备份find $BACKUP_DIR -name "all_*.sql.gz" -mtime +7 -deleteecho "Backup completed: all_$DATE.sql.gz"5. 备份策略建议全量备份:每天凌晨执行增量备份:每小时执行二进制日志:实时保留异地备份:定期同步到远程服务器备份验证:定期测试恢复流程6. 恢复注意事项恢复前先停止 MariaDB 服务确保有足够的磁盘空间恢复后验证数据完整性记录恢复过程和时间点在测试环境先验证恢复流程通过合理的备份策略和恢复流程,可以最大程度保障 MariaDB 数据的安全性和可靠性。
服务端阅读 02月21日 15:51

MariaDB 的分区表有哪些类型?如何创建和管理分区表?

MariaDB 的分区表(Partitioning)是将大表分割成更小、更易管理的部分的技术,可以显著提升查询性能和管理效率。1. 分区类型RANGE 分区-- 按日期范围分区CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, customer_id INT, amount DECIMAL(10,2)) PARTITION BY RANGE (YEAR(order_date)) ( PARTITION p2022 VALUES LESS THAN (2023), PARTITION p2023 VALUES LESS THAN (2024), PARTITION p2024 VALUES LESS THAN (2025), PARTITION pmax VALUES LESS THAN MAXVALUE);-- 按数值范围分区CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR(50), age INT) PARTITION BY RANGE (age) ( PARTITION p0 VALUES LESS THAN (18), PARTITION p1 VALUES LESS THAN (30), PARTITION p2 VALUES LESS THAN (50), PARTITION p3 VALUES LESS THAN MAXVALUE);LIST 分区-- 按离散值列表分区CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, region VARCHAR(20), amount DECIMAL(10,2)) PARTITION BY LIST COLUMNS(region) ( PARTITION p_east VALUES IN ('New York', 'Boston', 'Philadelphia'), PARTITION p_west VALUES IN ('Los Angeles', 'San Francisco', 'Seattle'), PARTITION p_midwest VALUES IN ('Chicago', 'Detroit', 'Cleveland'), PARTITION p_south VALUES IN ('Atlanta', 'Miami', 'Dallas'));HASH 分区-- 哈希分区(均匀分布数据)CREATE TABLE products ( id INT PRIMARY KEY, name VARCHAR(100), category_id INT, price DECIMAL(10,2)) PARTITION BY HASH(id) PARTITIONS 4;-- 线性哈希分区(更快但分布可能不均匀)CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT, order_date DATE, amount DECIMAL(10,2)) PARTITION BY LINEAR HASH(customer_id) PARTITIONS 8;KEY 分区-- KEY 分区(类似 HASH,使用主键或唯一键)CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR(50), email VARCHAR(100)) PARTITION BY KEY(id) PARTITIONS 4;2. 分区管理添加分区-- RANGE 分区添加新分区ALTER TABLE orders ADD PARTITION ( PARTITION p2025 VALUES LESS THAN (2026));-- LIST 分区添加新分区ALTER TABLE orders ADD PARTITION ( PARTITION p_other VALUES IN ('Other', 'Unknown'));-- HASH/KEY 分区增加分区数量ALTER TABLE products REORGANIZE PARTITION ( PARTITION p0, PARTITION p1, PARTITION p2, PARTITION p3) INTO ( PARTITION p0, PARTITION p1, PARTITION p2, PARTITION p3, PARTITION p4, PARTITION p5);删除分区-- 删除分区(同时删除数据)ALTER TABLE orders DROP PARTITION p2022;-- 删除所有分区(转换为普通表)ALTER TABLE orders REMOVE PARTITIONING;合并分区-- 合并 RANGE 分区ALTER TABLE orders REORGANIZE PARTITION p2022, p2023 INTO ( PARTITION p2022_2023 VALUES LESS THAN (2024));3. 分区查询-- 查看分区信息SELECT PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION, TABLE_ROWSFROM information_schema.PARTITIONSWHERE TABLE_NAME = 'orders';-- 查询特定分区SELECT * FROM orders PARTITION (p2023);-- 使用分区裁剪优化查询SELECT * FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01';4. 分区维护-- 检查分区ALTER TABLE orders CHECK PARTITION p2023;-- 优化分区ALTER TABLE orders OPTIMIZE PARTITION p2023;-- 分析分区ALTER TABLE orders ANALYZE PARTITION p2023;-- 修复分区ALTER TABLE orders REPAIR PARTITION p2023;5. 分区索引-- 创建本地索引(每个分区独立索引)CREATE INDEX idx_customer_id ON orders(customer_id);-- 创建全局索引(MariaDB 10.3+)CREATE UNIQUE INDEX idx_global ON orders(id);6. 分区使用场景时间序列数据CREATE TABLE logs ( id BIGINT PRIMARY KEY, log_time TIMESTAMP, message TEXT, level VARCHAR(10)) PARTITION BY RANGE (UNIX_TIMESTAMP(log_time)) ( PARTITION p2024_q1 VALUES LESS THAN (UNIX_TIMESTAMP('2024-04-01')), PARTITION p2024_q2 VALUES LESS THAN (UNIX_TIMESTAMP('2024-07-01')), PARTITION p2024_q3 VALUES LESS THAN (UNIX_TIMESTAMP('2024-10-01')), PARTITION p2024_q4 VALUES LESS THAN (UNIX_TIMESTAMP('2025-01-01')));大表归档-- 定期归档旧数据ALTER TABLE orders DROP PARTITION p2022;7. 分区注意事项分区键选择:选择查询中常用的列作为分区键分区数量:不宜过多,建议 10-100 个分区主键约束:主键必须包含分区键唯一索引:唯一索引必须包含分区键数据分布:确保数据在各分区间均匀分布维护成本:分区表需要额外的维护操作分区表是处理大数据量的有效手段,合理使用可以显著提升查询性能和管理效率。
服务端阅读 02月21日 15:51

MariaDB 和 MySQL 有什么区别?

MariaDB 是一个开源的关系型数据库管理系统,由 MySQL 的原始开发者创建,作为 MySQL 的直接替代品。它保持了与 MySQL 的高度兼容性,同时提供了更多的存储引擎、性能优化和新功能。主要区别包括:存储引擎:MariaDB 提供了更多存储引擎选择,如 Aria、ColumnStore、Spider、RocksDB 等,而 MySQL 主要使用 InnoDB 和 MyISAM。性能优化:MariaDB 在查询优化、索引处理、缓存机制等方面进行了改进,通常在相同硬件上性能优于 MySQL。功能特性:MariaDB 支持窗口函数(MySQL 8.0+ 才支持)更丰富的 JSON 功能支持支持动态列(Dynamic Columns)更好的复制和集群功能开源策略:MariaDB 采用完全开源的 GPL 许可证,而 MySQL 在 Oracle 收购后采用双重许可证。更新频率:MariaDB 发布新版本更频繁,包含更多创新功能。兼容性:MariaDB 10.x 之前版本与 MySQL 5.x 高度兼容,但后续版本逐渐分化。在实际应用中,选择 MariaDB 还是 MySQL 主要取决于具体需求、团队技术栈和对开源策略的偏好。