MySQL
MySQL
执行顺序
FROM
子句:选定数据来源的表。WHERE
子句:筛选出满足条件的行。GROUP BY
子句:对数据进行分组。HAVING
子句:筛选分组后满足条件的组。SELECT
子句:选择最终展示的列。ORDER BY
子句:对结果进行排序。LIMIT
子句:限制返回的行数。
优化MySQL查询
- 使用索引:为频繁查询的列创建索引。
- 避免SELECT *:只选择所需的列减少数据传输。
- 使用JOIN而非子查询:在许多情况下,JOIN比子查询更高效。
- 分析查询:使用
EXPLAIN
命令查看查询的执行计划。 - 限制结果集:通过
LIMIT
减少返回的数据量。
聚合函数
聚合函数用于计算从多个行中生成单一值,常用于数据汇总分析。
常用的聚合函数包括:
COUNT()
:计算行数。SUM()
:计算总和。AVG()
:计算平均值。MIN()
:获取最小值。MAX()
:获取最大值。
事务
事务是一组SQL操作的集合,这些操作要么全部执行,要么不执行。事务提供了一种机制,以确保数据库在发生错误时能够回滚,防止数据不一致。
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
COMMIT; -- 或 ROLLBACK; 如果有错误发生
四大特性
原子性 (Atomicity):事务中的所有操作要么全部完成,要么全部不做。
一致性 (Consistency):事务执行前后,数据库的完整性约束需得到满足(字段的规定)。
隔离性 (Isolation):并发执行的事务互不干扰,每个事务的执行结果对其他事务不可见,直到该事务提交。
持久性 (Durability):一旦事务被提交,对数据库的修改是永久的,即使系统崩溃,数据也不会丢失。
视图
视图是一个虚拟表,它根据查询结果集动态生成,可以用于简化复杂查询、提高安全性和维护性。
生成后就相当于一个临时的表,可以对其使用sql语句。
CREATE VIEW it_employees AS
SELECT name, salary
FROM employees
WHERE department = 'IT';
SELECT * FROM it_employees;
变量和函数
变量和用户定义的函数可以存储临时数据和执行复杂的逻辑,增强SQL查询的灵活性。
- 变量: MySQL提供用户会话级别和全局级别的变量。会话变量在会话结束后失效,而全局变量在整个服务器范围有效。
- 用户定义的函数 (UDF): 可以创建自定义函数进行复杂的计算和操作,然后在SQL查询中使用。
-- 定义函数
DELIMITER //
CREATE FUNCTION add_two_numbers(a INT, b INT)
RETURNS INT
BEGIN
RETURN a + b;
END //
DELIMITER ;
-- 使用函数
SELECT add_two_numbers(5, 3); -- 返回结果为 8
使用变量:
SET @total_price = (SELECT SUM(price) FROM orders WHERE customer_id = 123);
SELECT @total_price; -- 显示客户123的总消费
FULLTEXT搜索
FULLTEXT索引允许对整列字符串进行全文搜索,支持多个关键字、布尔检索等功能。
先创建FULLTEXT索引:
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(255),
body TEXT,
FULLTEXT (title, body)
);
执行搜索:
SELECT * FROM articles
WHERE MATCH (title, body) AGAINST ('MySQL');
查询缓存
缓存查询结果,提高后续相同查询的响应速度,减少数据库负担。查询缓存会存储SELECT查询和对应的结果集。当相同的查询再次执行时,MySQL可以直接从缓存中返回结果,而不需再次访问原始表。
如果该查询结果被缓存,那么后续对相同查询的执行会直接返回缓存结果,而不必重新读取products
表。如果进行的UPDATE或INSERT改变了缓存的相关数据,MySQL会自动更新或失效缓存。
存储引擎
如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。MySql数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据自己的需要编写自己的存储引擎。
- MyISAM:这种引擎是mysql最早提供的。这种引擎又可以分为静态MyISAM、动态MyISAM 和压缩MyISAM三种,不管是何种MyISAM表,目前它都不支持事务,行级锁和外键约束的功能。
- InnoDB表类型可以看作是对MyISAM的进一步更新产品,它提供了事务、行级锁机制和外键约束的功能,也是目前MySQL默认的存储引擎。
在电商应用中,使用InnoDB
存储订单数据以支持并发操作和数据一致性,而采用MyISAM
存储商品类别数据,以便快速的全文搜索和读取性能。当操作频繁且需要支持事务时,推荐使用InnoDB。
外键FOREIGN KEY
外键约束定义了一列或多列在一个表中必须与另一个表中的主键或唯一键相匹配,确保数据的对应关系。
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
amount DECIMAL(10, 2),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
orders
表的customer_id
是外键,它保证了每个订单都属于有效的客户。如果尝试插入一个不存在的customer_id
,数据库将返回错误,从而保护数据的一致性。
逻辑与物理备份
逻辑备份:使用SQL文件导出数据库结构和数据(如mysqldump
)。备份较小,易于维护,但恢复速度可能较慢。
mysqldump -u root -p mydatabase > mydatabase_backup.sql
物理备份:复制数据库文件(如datadir
目录),可快速恢复,但需确保正确的数据库状态进行备份。
cp -r /var/lib/mysql/mydatabase /backup/mydatabase_backup
然后可以选择恢复方式:
- 使用
mysql
命令导入逻辑备份。 - 直接复制物理备份文件至数据目录并重启MySQL。
高并发情况下安全地修改同一行数据(锁)
- 行级锁:只锁定被修改的行,使其他操作可以继续。
- 乐观锁:基于版本号或时间戳,检测数据是否被修改,进行冲突检测。
- 悲观锁:在操作前获取锁,直到操作完成,避免其他事务访问。
处理和优化重复数据
- 使用
DISTINCT
关键字查询去重的结果。 - 利用
GROUP BY
及聚合函数统计重复的行。 - 创建唯一约束(
UNIQUE
)防止后续插入重复数据。
id | |
---|---|
1 | [email protected] |
2 | [email protected] |
3 | [email protected] |
查找重复的email:
SELECT email, COUNT(*) AS count
FROM customer_emails
GROUP BY email
HAVING count > 1;
去重:
ALTER TABLE customer_emails
ADD CONSTRAINT unique_email UNIQUE (email);
三范式
范式是数据库设计中用于减少冗余和防止数据异常的原则:
- 第一范式 (1NF):确保表中每个列只保存原子值,避免重复列和多值属性。
- 第二范式 (2NF):在满足1NF的基础上,每个非主键列必须完全依赖于主键。
- 第三范式 (3NF):在满足2NF的基础上,非主键列不能依赖于其他非主键列。
分布式数据库
可以将大规模的数据根据某个标准(如用户ID)进行分片。比如将用户数据划分至不同的数据库实例:
db1
存储用户ID0-1000
db2
存储用户ID1001-2000
管理分布式数据库的工具,如基于Zookeeper的分布式锁和协调服务,保障多个节点数据的一致性。
设计主键和索引
根据查询模式、数据增长趋势重评现有的主键和索引,有时需要进行拆分、合并或变更类型。
分布式事务
分布式事务用于保证跨多个数据库的操作要么全部成功,要么全部回滚,以保持数据的一致性。实现分布式事务通常使用两阶段提交协议(2PC)或更复杂的分布式事务管理器(如XA)来协调参与方的成功或失败。
关于索引
索引是一种数据结构,MySQL通过它减少了需要扫描的行数,从而加速了查询。使用合适的索引,可以使查询时间从O(n)降低到O(log n)或更快。有了这个索引后,MySQL可以直接通过索引查找符合条件的行,而不是遍历整个表,从而加快查询速度。索引可以是单列索引或多列索引,且必须在WHERE子句、JOIN条件和ORDER BY等场景中使用。
索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,在数据十分庞大的时候,索引可以大大加快查询的速度,这是因为使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据。
创建时添加:
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);
创建后添加:
ALTER TABLE my_table ADD [UNIQUE] INDEX index_name(column_name);
或者
CREATE INDEX index_name ON my_table(column_name);
索引需要占用****磁盘空间****,因此在创建索引时要考虑到磁盘空间是否足够
创建索引时需要对表加锁,因此实际操作中需要在业务空闲期间进行
优势:可以快速检索,减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序;
劣势:索引本身也是表,因此会占用存储空间,一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表。
类型有:
- B-Tree索引: 默认索引类型,适用于范围查询。
- 哈希索引: 适用于等值查询,只能用于Memory存储引擎。
- 全文索引: 用于文本搜索(如FULLTEXT)。
- 空间索引: 用于处理地理数据。
处理和优化大型UPDATE操作
优化大型UPDATE操作可以减少锁竞争,提高系统响应速度,避免长时间的阻塞。
- 分批执行: 将大型更新操作分成多个小批次执行,以降低对数据库的负担。
- 关闭自动提交: 在执行大型更新时,暂时关闭自动提交以减少日志写入量。
- 使用WHERE条件: 确保更新仅作用于必要的行,以减少受影响行数。
- 索引优化: 确保更新涉及的列有合适的索引。
优化前:
UPDATE employees SET salary = salary * 1.1;
分批优化后:
SET @row_count = 1;
WHILE @row_count > 0 DO
UPDATE employees SET salary = salary * 1.1 LIMIT 500;
SET @row_count = ROW_COUNT();
END WHILE;
优化COUNT()查询
- 使用索引: COUNT(*) 通过索引可以显著快于全表扫描。
- 避免使用*字段: COUNT(field_name) 如果列含有NULL,则可能低估计行数。
- 使用预先计算的结果: 将统计结果存储在缓存表中,尤其是对于频繁查询的统计。
优化的步骤方法
SQL优化的一般步骤包括:
识别慢查询: 使用 slow_query_log。
添加适当索引: 针对查询条件添加索引。
重写查询: 尝试不同的查询方式或使用表连接。
利用EXPLAIN: 理解 SQL 查询的执行过程。
EXPLAIN命令提供了查询的执行计划、使用的索引、行数估算等信息。
EXPLAIN SELECT * FROM employees WHERE department_id = 5;
会显示使用的索引、扫描的行数等信息,帮助识别查询瓶颈。
MySQL如何执行子查询,以及它们的性能影响是什么
子查询用于从一个查询的结果中作为另一个查询的输入,能提供灵活的数据检索。性能方面,子查询通常比JOIN更慢,因为每个子查询可能都是一个独立的SELECT语句,有时MySQL会执行多次。
要按编号查找所有在HR部门工作的员工:
SELECT * FROM employees WHERE department_id = (SELECT id FROM departments WHERE name = 'HR');
join优化:
SELECT e.* FROM employees e JOIN departments d ON e.department_id = d.id WHERE d.name = 'HR';
这个改写使得一次性从departments
中查询后再与employees
表连接。
批量插入数据优化
使用INSERT…VALUES多值插入: 一个查询插入多行,减少网络往返。
INSERT INTO employees (name, salary) VALUES ('John', 5000), ('Jane', 5500), ('Bob', 6000);
关闭自动提交: 收集多个插入操作再一起提交,减少每次插入的开销。
LOAD DATA INFILE: 用于大量数据的快速加载。
LOAD DATA INFILE '/path/to/file.csv' INTO TABLE employees FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' IGNORE 1 ROWS;
优化ORDER BY查询
在需要排序的字段上建立索引后,MySQL能直接使用索引而非全表扫描来排序,从而提升性能。
优化DISTINCT查询
- 使用索引: 确保DISTINCT字段有索引。
- 只选择必要列: 精简SELECT中需要的数据列。
- 考虑表的结构: 对于小表,可能不需DISTINCT。
MySQL中的事务隔离级别以及它们如何影响并发
READ UNCOMMITTED: 最低级别,事务可以读取未提交的数据,可能导致脏读。
READ COMMITTED: 提高了数据一致性,事务只能读取已提交的数据,但仍可能导致不可重复读。
REPEATABLE READ: 默认级别,确保在同一事务中多次查询同一数据的结果相同,避免不可重复读,但可能导致幻读。
SERIALIZABLE: 最高级别,强制事务串行执行,完全避免脏读、不可重复读与幻读,但相应地降低并发性。
死锁是如何产生的,如何预防和解决
死锁是指两个或多个事务在执行过程中,各自持有对方所需的锁资源,导致所有事务无法继续执行。死锁通常发生于两个事务分别锁定了对方需要的资源。
预防:
- 尽量按相同顺序获取锁。
- 使用较低的事务隔离级别。
- 对事务进行重试。
如何处理死锁
MySQL会自动检测死锁,并选择自动回滚一个事务来解除死锁。被回滚的事务会被复位为未提交状态,允许其它事务继续执行。
假设存储引擎(如InnoDB)检测到死锁,它会回滚正在休眠的事务(如事务A或B),以允许其他事务继续运行。数据库会返回一个错误。应用程序应该捕获这个错误,再次尝试执行被回滚的事务。
多个版本并发控制(MVCC)
MVCC是一种并发控制机制,允许多个事务并发执行,在不加锁的方式下确保事务一致性。在更新数据的同时,保留数据的多个版本以供读取。这使得读取操作不会被写入阻塞,从而提高性能。
考虑两个事务T1和T2:
- T1读取数据版本V1,T2在其上提交更改并生成V2。
- T1继续进行,认为自己仍在工作在旧的V1上,不受T2影响。
数据库锁和表锁
数据库锁:用于在数据库级别锁定整个数据库,使得在锁定期间,其他用户无法对该数据库的任何表进行操作。适用于需要对整库操作的场景,但会影响其他用户的访问效率。
表锁:锁定指定的表以防止其他用户对该表的读写。表锁比数据库锁更细粒度,可以减少对其他表操作的影响,但在高并发场景下,可能导致等待时间增加。
锁升级
锁升级是为了减少锁的数量,从而提高性能和避免死锁的机制。
在MySQL中,如果多个行被锁定,且锁的数量达到一定量,MySQL系统可能会自动将行锁(更细粒度的锁)升级为表锁(更粗粒度的锁)。这是为了优化性能和减少锁的管理开销。但是,这种操作也可能在高并发环境下引发的问题,比如延迟或阻塞。
在MySQL中监控数据库及查询慢日志
数据库监控:可以利用MySQL的性能模式(Performance Schema)或者信息模式(Information Schema)来监控数据库的运行状态。 监控内容包括但不限于查询执行时间、活动线程数、锁等待等。
慢查询日志:通过设置slow_query_log变量为ON,并配置long_query_time,可以记录执行时间超过指定阈值的SQL语句。
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2; -- 记录执行超过2秒的查询
然后使用SHOW VARIABLES LIKE 'slow_query_log';
查看当前慢查询日志的状态。
INDEX覆盖扫描
INDEX覆盖扫描允许数据库只使用索引来满足查询,而不需访问表数据行。
当查询字段都在某个索引里,数据库就可以直接通过访问索引来获取结果,而不需要再去读取数据行,从而减少IO操作,提高查询性能。
假设对employees
表有一个包含name
和department
的索引,因为name
和department
都在索引中,MySQL仅会使用索引,而无需去查找数据表,从而优化查询性能。
IN与JOIN操作有什么性能差异
- IN操作:通常用于子查询中,将一个结果集用作当前查询的过滤条件,直接从结果集中匹配数据。
- JOIN操作:用于将两个或多个表结合起来,基于共享的列进行比对。
使用EXISTS优化
EXISTS用于测试子查询的结果是否存在,有助于避免不必要的数据处理。EXISTS会在找到满足条件的第一条记录后立即返回,避免了不必要的计算。
SELECT * FROM departments d WHERE EXISTS (SELECT * FROM employees e WHERE e.department_id = d.id);
在这种情况下,一旦找到一个匹配,EXISTS就会立即返回,而没有必要检查所有记录,从而提高查询效率。
联合索引
联合索引允许在一个索引中包含多个列,以优化多列查询的性能。MySQL会考虑索引的列顺序,查询条件必须遵循最左前缀规则。
如果我们创建如下联合索引:
CREATE INDEX idx_dept_salary ON employees(department_id, salary);
对应查询应优先使用department_id
进行过滤,对于只使用salary
的查询,索引不一定能被利用,从而影响效率。
索引合并
在某些情况下,MySQL会在执行查询时将多个索引结合在一起,从而返回所需的结果。这个过程被称作“索引合并”,它可以提高查询效率,尤其在查询条件涉及多个列时。
分区索引
分区索引是对一个表进行分区存储的数据的索引结构。通过将大表分成多个 “分区”,分区索引允许MySQL在查询时只访问相关的分区,而非整个表。这可以显著提升查询性能,尤其在处理大量数据时。
按年份分区的logs
表,查询某一年份的数据:
SELECT * FROM logs PARTITION (p2023) WHERE event_type = 'error';
MySQL只访问p2023
分区,从而加快查询速度。
索引前缀
当表中的某一列长度很大时,可以创建该列的前缀索引,以减少索引的占用。这种方法尤其适用于VARCHAR列,能够优化性能。
创建一个仅针对name
前10个字符的索引:
CREATE INDEX idx_name_prefix ON employees(name(10));
物化视图
物化视图将视图的查询结果存盘存储,而不是每次访问时实时执行查询。相较于普通视图,物化视图在性能方面优异,尤其在查询执行频繁的情况下。
MySQL默认不支持,可以模拟:
CREATE TABLE materialized_view AS SELECT * FROM large_table WHERE condition;
触发器
触发器是一种特殊的存储过程,用于自动响应数据表中的插入、更新或删除事件。
当满足特定条件时,触发器会自动执行预定义的操作进行数据完整性检查和维护。
在插入时记录日志:
CREATE TRIGGER before_insert_employees
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
INSERT INTO employees_log (emp_id, action) VALUES (NEW.id, 'insert');
END;
触发器类型
- BEFORE触发器:在执行插入、更新、删除操作之前触发,适合修改即将写入的数据。
- AFTER触发器:在执行操作后触发,适合用于日志记录和后续操作。
数据压缩
在MySQL中使用InnoDB或MyISAM存储引擎时,可以通过对表或索引进行压缩来实现数据压缩。
- 行压缩:InnoDB提供
ROW_FORMAT=COMPRESSED
选项来压缩行数据。 - 表压缩:对于MyISAM,可以使用
MYISAM_DATA
和MYISAM_INDEX
的压缩选项。
创建压缩表示例:
CREATE TABLE my_table (
id INT,
name VARCHAR(100)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
空间数据类型
空间数据类型用于存储和处理地理数据,为GIS(地理信息系统)应用提供支持。
MySQL支持多种空间数据类型,包括:
POINT
:表示一个位置。LINESTRING
:表示一条线或路径。POLYGON
:表示一个多边形区域。
这些数据类型使得MySQL可以执行一些地理空间运算,例如距离计算、区域重叠等。
优化大表性能
- 索引:为表创建适当的索引来加速查询。
- 分区:使用分区表可以将大表分成小块,改善查询和维护性能。
- 归档:定期归档不再活跃的数据,保持表的大小适中。
- 查询优化:使用
EXPLAIN
分析查询,寻找并改进慢查询。
FLUSH命令
FLUSH
命令用于清除或刷新MySQL的不同缓存、日志和表状态,确保数据一致性和性能优化。
FLUSH TABLES
:关闭当前打开的所有表并释放内存。FLUSH LOGS
:关闭当前日志文件并创建一个新的日志文件。FLUSH PRIVILEGES
:重新加载授权表。
窗口函数
窗口函数用于在行集上执行计算,允许在查询的每行中访问其他行的数据,通常用于分析和聚合操作。窗口函数不改变结果集的数量,类似于使用聚合函数但不需要使用GROUP BY
,它允许在结果集中保留非聚合列。
使用窗口函数进行排名:
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employees;
自适应哈希索引
自适应哈希索引是一种动态创建的索引,它提高了查询的速度,当MySQL内部检测到某些查询分组或索引操作时,自动生成哈希索引。
自适应哈希索引在内存中创建,并随着数据的变化自动调整,从而能够更快地访问经常使用的表数据。但是,对每个表的自适应哈希索引使用是有限的。
启用自适应哈希索引:
SET GLOBAL innodb_adaptive_hash_index = ON; -- 默认启用
主从复制
主从复制用于数据备份和负载均衡,通过不同的数据库节点保证数据的高可用性和容错能力。
实现步骤包括设置主服务器和从服务器的配置,使用二进制日志(binlog)记录主服务器的写入操作并传送到从服务器。
复制延迟
复制延迟是指从服务器的状态滞后于主服务器的状态,可能导致数据不一致和实时性问题。
复制延迟的原因包括网络延迟、从服务器负载过重、慢查询等,可以通过监控Seconds_Behind_Master状态变量来检查延迟。
监控复制延迟:
SHOW SLAVE STATUS\G; -- 查看详细的从服务器状态
临时表
临时表在创建时只对创建它的会话可见,随着会话的结束而自动删除,可以用来处理复杂的查询和数据计算。 创建临时表:
CREATE TEMPORARY TABLE temp_table AS
SELECT * FROM my_table WHERE condition;
如何确保数据的完整性和一致性
主键和外键约束:主键确保每条记录的唯一性,外键约束则确保引用完整性,即确保表与表之间的关系有效。
检查约束:通过CHECK约束,可以限制列中的数据值范围,确保数据的有效性。
事务管理:使用ACID(原子性、一致性、隔离性、持久性)特性,确保数据库的操作在逻辑上是完整的,可以通过COMMIT和ROLLBACK来管理事务。
触发器:可以使用触发器在特定操作(如插入、更新、删除)时执行一些自定义规则以保持数据一致性。
数据脱敏
在MySQL中进行数据脱敏的常用方法包括:
数据掩码:对敏感数据进行部分隐藏,如将身份证号显示为“******1234”。
数据哈希:使用哈希算法(如MD5或SHA)对敏感信息进行处理,存储其哈希值,而非明文。
替换:用随机或静态的非真实数据替换敏感字段,确保不漏泄真实信息。
使用加密:将敏感信息加密存储,在需访问时进行解密,再加以使用。
例如,可以使用下面的SQL语句对员工表中的邮箱进行数据脱敏处理:
UPDATE employees
SET email = CONCAT('user', id, '@example.com');
MySQL中的分区表
MySQL中的分区表能够根据某些列的值将数据分割成多个子表,常见的分区方式包括:
- Range 分区:通过指定一个范围来分区,例如按日期范围划分。
- List 分区:针对特定的值进行分区。
- Hash 分区:通过散列函数对数据分配到不同分区。
- Key 分区:使用MySQL的内置散列函数,将数据分配到分区。
通过分区,可以提升性能,因为查询只需要扫描相关的分区而非整个表。
按年份进行分区:
CREATE TABLE sales (
id INT,
amount DECIMAL(10,2),
sale_date DATE
) PARTITION BY RANGE (YEAR(sale_date)) (
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023)
);
假如查询2021年的销售记录,可以仅访问p2021分区,大大提高查询速度。
分布式架构和复制策略
在MySQL中,分布式架构通常涉及到以下几种复制策略:
- 主从复制:一个主数据库可以有多个从数据库,从数据库不断从主数据库复制更新,适用于读负载分担。
- 主主复制:两个主数据库互相复制,根据负载情况分担写操作,适合多个地理位置的数据库。
- 半同步复制:主库在确认至少有一个从库接收到数据后,才认为操作成功,增强数据的可靠性。
- 数据分片(Sharding):将数据水平分割,通过不同的数据库存储,允许更好的负载分配与扩展。
处理并发链接
MySQL通过多个机制处理并发连接,包括:
- 线程池:管理数据库线程,有效地使用连接资源。
- 连接限制:可以通过参数(如max_connections)限制最大连接数,防止资源耗尽。
- 锁机制:使用行级锁或表级锁来处理数据的并发访问,确保数据的一致性。
- 查询缓存:在适当的情况下,缓存查询结果而不必每次都重新处理相同的请求。
处理NULL值
- 使用IS NULL或IS NOT NULL:查询中可以使用这些条件进行NULL值的处理。
- 默认值:在列定义时,考虑使用默认值避免NULL。
- 聚合函数:在聚合操作中,NULL值会被忽略,需要注意此行为。
索引分类
常见的索引类型有:主键索引、唯一索引、普通索引、全文索引、组合索引
1、主键索引:即主索引,根据主键pk_clolum(length)建立索引,不允许重复,不允许空值;
ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col');
2、唯一索引:用来建立索引的列的值必须是唯一的,允许空值
ALTER TABLE 'table_name' ADD UNIQUE index_name('col');
3、普通索引:用表中的普通列构建的索引,没有任何限制
ALTER TABLE 'table_name' ADD INDEX index_name('col');
4、全文索引:用大文本对象的列构建的索引(下一部分会讲解)
ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col');
5、组合索引:用多个列组合构建的索引,这多个列中的值不允许有空值
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
遵循“最左前缀”原则,把最常用作为检索或排序的列放在最左,依次递减,组合索引相当于建立了col1,col1col2,col1col2col3三个索引,而col2或者col3是不能使用索引的。
在使用组合索引的时候可能因为列名长度过长而导致索引的key太大,导致效率降低,在允许的情况下,可以只取col1和col2的前几个字符作为索引
ALTER TABLE 'table_name' ADD INDEX index_name(col1(4),col2(3));
索引实现原理
1、哈希索引:
只有memory(内存)存储引擎支持哈希索引,哈希索引用索引列的值计算该值的hashCode,然后在hashCode相应的位置存该值所在行数据的物理位置,因为使用散列算法,因此访问速度非常快,但是一个值只能对应一个hashCode,而且是散列的分布方式,因此哈希索引不支持范围查找和排序的功能。
2、全文索引:
FULLTEXT(全文)索引,仅可用于MyISAM和InnoDB,针对较大的数据,生成全文索引非常的消耗时间和空间。对于文本的大对象,或者较大的CHAR类型的数据,如果使用普通索引,那么匹配文本前几个字符还是可行的,但是想要匹配文本中间的几个单词,那么就要使用LIKE %word%来匹配,这样需要很长的时间来处理,响应时间会大大增加,这种情况,就可使用时FULLTEXT索引了,在生成FULLTEXT索引时,会为文本生成一份单词的清单,在索引时及根据这个单词的清单来索引。FULLTEXT可以在创建表的时候创建,也可以在需要的时候用ALTER或者CREATE INDEX来添加。
3、BTree索引和B+Tree索引
Group by和having的区别
group by用作分组统计:
SELECT category, SUM(quantity * price) AS total_sales
FROM sales
GROUP BY category;
category | total_sales
------------|------------
Books | 150
Electronics | 1050
Furniture | 800
having用来过滤:
SELECT category, SUM(quantity * price) AS total_sales
FROM sales
GROUP BY category
HAVING total_sales > 10000;
锁的实现
InnoDB实现了两种标准的行级锁: