mysql易学难精
Mysql的架构介绍
mysql简介
mysql概述
mysql优化
mysql5.5安装:
yum下载的mysql是5.1版本,但我们需要至少5.5版本
1、方法一
mysql开发者相关文档 https://dev.mysql.com/downloads/mysql/
下载5.5教程https://www.cnblogs.com/littlemonsterksn/p/10154662.html
wget是Linux系统中的一个下载文件的命令工具。对于经常要下载一些软件或从远程服务器恢复备份到本地服务器的用户来说是必不可少的工具。
没有wget就下一个:yum -y install wget
得到安装包:mysql-5.5.62-linux-glibc2.12-x86_64.tar.gz,解压后安装
方法二
在资料中找到了对应mysql5.5的rpm包,本地上传到Linux
pscp -r D:\MySQL\MySQL高级\mysql5.5.48 root@192.168.1.15:/opt
上传成功
1 | mysqladmin --version有东西说明安装成功 |
top命令后,实时显示系统中各个进程的资源占用状况,即当前系统正在执行的进程的相关信息,包括进程ID、内存占用率、CPU占用率等。
可以参考:
https://www.cnblogs.com/peida/archive/2012/12/24/2831353.html
设置开机自启动mysql
1 | chkconfig mysql on |
看到【*】mysql,表示开机后 自动启动mysql(带星号表示,开机自启动,反之相反)
修改配置文件位置:
将 /usr/share/mysql/my-huge.cnf拷贝到/etc下
cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
1 | service mysql stop |
修改字符集和数据存储路径:
1 | show variables like 'character%'; |
在 /etc/my.cnf对应位置修改
修改完成后重新启动mysql,添加数据还是中文乱码原因:配置文件没错,否者不能重新启动mysql,乱码的原因是库在修改配置之前建立,因此装完mysql之后应该立即修改配置文件。
MySQL的安装位置——在linux下查看安装目录ps -ef|grep mysql
mysql存储引擎:
查看命令:
两种引擎可否混用?
引擎是针对表,而不是针对库的,在建表的时候声明成不同的引擎即可。 比如: CREATE TABLE test_1
( name
varchar(20) DEFAULT NULL, year
int(5) DEFAULT NULL ) ENGINE=MyISAM
两种存储引擎区别
阿里巴巴、淘宝用哪个
索引优化
性能下降SQL慢、执行时间长、等待时间长的原因
1 | 1.查询语句写的烂 |
索引写操作
索引主要分类:
1.主键索引 2.唯一索引3.普通索引 4.组合索引5.全文索引
索引CREATE创建
1 | CREATE INDEX index_name ON table_name (col_name,...) |
在MySQL中,默认情况下,一个查询只能使用一个索引来访问数据。
不过,MySQL支持索引合并,允许在某些特定条件下使用多个索引。
索引合并
1.并集合并(Union Merge)
当查询的 WHERE
子句中包含多个条件,且这些条件之间使用 OR
连接时,MySQL 会分别扫描每个条件对应的索引,然后取结果的并集。
1 | SELECT * FROM table WHERE key1 = 'value1' OR key2 = 'value2'; |
如果 key1
和 key2
列上都有索引,MySQL 可能会选择使用并集合并策略,分别扫描这两个索引,获取满足每个条件的记录,然后合并结果集,返回满足任一条件的用户记录
2.交集合并(Intersection Merge)
查询的 WHERE
子句中包含多个条件,且这些条件之间使用 AND
连接时,MySQL 会分别扫描每个条件对应的索引,然后取结果的交集。
1 | SELECT * FROM users WHERE first_name = 'John' AND last_name = 'Doe' AND age = 30; |
如果 first_name
、last_name
和 age
列上都有单独的索引,MySQL 的查询优化器可能会选择使用交集合并策略,分别扫描这三个索引,获取满足每个条件的记录,然后取这些记录的交集作为最终的结果集。
3.排序并集合并(Sort-Union Merge)
适用于 OR
连接的条件,特别是当涉及范围查询时。在这种情况下,MySQL 会先对每个索引查找的结果进行排序,然后再进行合并
1 | SELECT * FROM table WHERE col1 < value1 OR col1 > value2; |
不适合索引合并的情况:
1.索引合并主要适用于 B-tree 索引,全文索引不支持索引合并。
2.对于存在范围查询(如 BETWEEN
、<
、>
等)或 ORDER BY
子句的查询,MySQL 可能不会使用索引合并,而是选择使用单个索引或进行全表扫描。
3.如果某个索引的选择性较差(即该索引列中有大量重复值,区分度较小),查询优化器可能不会选择该索引进行合并。
当两个表 JOIN
时,如果两个表的索引都被使用,这表明每个表都利用了自己的索引进行高效的查找。这是独立索引的使用,不是索引合并。索引合并是MySQL 中一种用于在单个表上使用多个索引的优化策略。
单值索引和复合索引如何选择
单值索引
1 | 优点: |
复合索引
1 | 高性能:对于涉及多个列的查询条件,复合索引可以显著提高查询效率,尤其是当查询条件中的列顺序与复合索引的列顺序匹配时。 |
- 选择复合索引的场景:
- 查询条件中经常同时使用多个列。
- 查询条件中的列具有明显的过滤顺序(某些列的过滤效果更好)。
- 查询可以被复合索引覆盖(覆盖索引)。
- 选择单值索引的场景:
- 表中的查询条件通常只涉及单个列。
- 表需要支持多种不同的查询条件组合,难以通过复合索引来覆盖所有情况。
- 表的插入、更新和删除操作非常频繁,且对性能要求较高。
ALTER命令添加数据表索引:
1.添加一个主键,意味着索引值必须是唯一的,且不能为NULL。
1 | ALTER TABLE tbl_name ADD PRIMARY KEY (column_list) |
2.这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
1 | ALTER TABLE tbl_name ADD UNIQUE index_name(column_list) |
3.添加普通索引,索引值可出现多次。
1 | ALTER TABLE tbl_name ADD INDEX index_name(column_list) |
4.该语句指定了索引为FULLTEXT,用于全文索引
1 | ALTER TABLE tbl_name ADD FULLTEXT index_name(column_list) |
全文索引可以高效地支持复杂的文本搜索操作,适用于**TEXT
、VARCHAR
、CHAR
**类型字段
删除索引
1 | DROP INDEX index_name ON talbe_name |
mysql300万记录以内没问题,超过就需要优化。
常见通用的Join查询
SQL执行顺序
手写
机读
join关联图:内连接、外连接( 左(外)连接、右(外)连接、全(外)连接)、笛卡尔积
join 等同于 inner join,默认是内连接.
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录。
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录。
inner join(等值连接) 只返回两个表中联结字段相等的行。
1 | select * from A inner join B on A.id = B.id; |
MySQL不支持全外连接,但可以模拟,详细看《笛卡尔积-内连接-外连接》。
join语句优化:
主键自带主键索引(不需要建立)
尽可能减少join语句中NestedLoop的循环总次数(不要join过多或嵌套);
永远用小表驱动大表(根据数据量大小区分大表和小表,嵌套循环访问,详细看后面扩展);
优先优化NestedLoop的外层循环(即驱动表),其次是内层循环(被驱动表);
保证join语句中被驱动表(大表)上join字段已经被索引;
当无法保证被驱动表的join条件字段被索引,在内存资源充足的前提下,不要吝啬JoinBuffer的设置;
驱动表的索引优化是为了减少外层循环的次数,而内层循环的优化是为了减少每次内层循环的执行时间,两者相辅相成。
查询优化——永远小表驱动大表类似全套循环NestedLoop,这里的“小表”和“大表”是相对的,指的是表的数据量大小。
扩展
1 | NestedLoop的工作原理————所谓嵌套 |
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 100 | NULL |
1 | SIMPLE | t2 | ref | t1_id | t1_id | 4 | t1.id | 10 | Using index |
1 | SIMPLE | t3 | ref | t2_id | t2_id | 4 | t2.id | 5 | Using index |
1 | explain可以查看查询执行计划,从而确定哪个表是驱动表,哪个表是被驱动表。 |
性能分析
MySql Query optimizer(mysql查询优化器)
-
MySql中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
-
MySQL Query Optimizer工作流程
1)当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出是SELECT并转发给MySQL Query Optimizer。
2)MySQL Query Optimizer首先会对整条Query进行优化,将一些常量表达式换算成常量值,并对查询条件进行简化和转换(如去掉一些无用或显而易见的条件、结构调整等)。1
2
3
4
5
6
7
8
9
10比如:
SELECT * FROM table WHERE 1=1 AND column = 'value';
简化处理后
SELECT * FROM table WHERE column = 'value';
SELECT * FROM table WHERE column = 'value1' OR column = 'value2' OR column = 'value3';
转为:
SELECT * FROM table WHERE column IN ('value1', 'value2', 'value3');
即常量表达式计算、去掉无用的条件、去掉冗余的条件、转换OR为IN、 转换子查询为连接查询、转换连接查询(join)为子查询、转换OR条件为UNION、转换DISTINCT为GROUP BY等3)然后分析Query中的Hint信息(如果有),看显示的Hint信息是否可以完全确定该Query的执行计划。如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。
1
2
3
4
5
6
7
8
9
10
11
12hint信息:hint(提示)是用户给数据库查询优化器的指令,用于指定查询的执行计划或影响优化器的选择。
MySQL提供了多种类型的hint,比如USE INDEX:
SELECT /*+ USE INDEX (idx_column1) */ column1, column2
FROM table
WHERE column1 = 'value1';
或者IGNORE INDEX:
SELECT /*+ IGNORE INDEX (idx_column1) */ column1, column2
FROM table
WHERE column1 = 'value1';
还有:FORCE INDEX、JOIN ORDER、MAX_EXECUTION_TIME。
hint信息是用户(如开发者或数据库管理员)根据对查询和数据库的理解,手动添加到SQL语句中的特殊指令。在大多数情况下,数据库的查询优化器能够自动为查询生成高效的执行计划,因此hint不是必需的。只有在查询优化器无法生成理想执行计划,且用户认为自己可以指定更好的计划时,才会考虑使用hint。hint不仅可以由数据库管理员(DBA)使用,也可以由应用开发者在编写SQL语句时添加。
mysql常见瓶颈(略)
1 | 1.查询性能瓶颈 |
Explain关键字:
https://www.cnblogs.com/dlp-527/p/11824467.html
用法:Explain+SQL语句,可以获取 SQL 查询的执行计划(执行计划是数据库查询优化器决定如何执行查询的详细步骤)。
id:查询中每个子查询或表的执行顺序标识符,id
相同,表示这些查询可以并行执行; id
不同,数字越大,优先级越高,越先被执行。
select_type:查询类型,描述了查询中每个 SELECT
子句的性质。常见的类型包括 SIMPLE
(简单查询)、PRIMARY
(主查询)、SUBQUERY
(子查询)、UNION
(联合查询的一部分)、derived
(表示该查询是一个派生表)等。
table:显示与查询相关的表的名称。通过观察table
列的顺序,可以确定查询中表的访问顺序。通常,第一个表(id
最小的表)是驱动表,后续的表是被驱动表。
partitions:指示查询访问的表的分区信息(如果表被分区),不常用。
type: 查询类型,指示查询优化器如何访问表中的数据,这个字段的值对查询性能有很大影响。
possible_keys:表示查询优化器可能使用的索引,用于提高查询速度
**key:**表示实际被使用的索引。
key_len:表示在查询中实际使用的索引字段数据的长度,以字节为单位。
1 | 对于单值索引 |
**ref:**指示与索引列进行比较的列或常量。
rows:表示查询优化器预计需要扫描的行数。这个值越小,查询性能越好。
filtered:表示查询优化器预计经过过滤后保留的行的百分比,值越高,说明筛选条件越严格。
Extra:额外的比较重要的信息,如 Using where
(使用了 WHERE
条件过滤结果)、Using index
(表示使用索引覆盖查询,无需回表查询)、Using filesort
(需要额外的排序操作)、Using temporary
(使用了临时表)、Using join buffer
(表示使用连接缓冲区)等。
拓展:
select_type中的DERIVED:表示这个查询后的结果是一个派生表,即查询的结果被当作一个临时表使用,通常这个临时表是由子查询的结果构成的,也称为子查询或内联接子查询。派生表可以包含在主查询的 FROM
子句中,就像它是一个普通表一样,允许你对子查询的结果进行操作,比如进一步的筛选、排序或联接其他表。
当 select_type
为 DERIVED
时,这通常意味着查询优化器会递归执行子查询,并将结果放入一个临时表中,然后主查询可以使用这个临时表。这种派生表的使用可能会影响查询性能,特别是当子查询复杂或返回大量数据时。在优化查询时,考虑将派生表转换为连接(JOIN)或其他形式,可能会提高效率。
**type:**又称“访问类型”,表示表连接的类型,反映了MySQL决定如何查找表中的行。是较为重要的一个指标。结果从最好到最坏依次是:
1 | system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL |
type为all的地方,通常需要进行优化,一般需要达到 ref、eq_ref 级别,范围查找需要达到 range。
例子:
id=2,最先执行,select_type为DERIVED表示这个查询的结果是一个派生表。也就是在 FROM
子句中的子查询,其结果被当作一个临时表来使用。在这个例子中,子查询 select * from t1 where id = 1
就是一个派生表,别名为 d1
。它是where等值查询主键,type为const,常量表查找。
id=1,为外面一层查询,select_type为PRIMARY,是主键查询,table 为 <derived2>
, <derived2>
表示这是第二个查询(主查询中的派生表)的结果集,实际上对应的是 d1
这个派生表,type为system,派生表d1是一个只有一行的表,所以连接类型为 system
。
extra:额外的比较重要的信息,包含了查询优化器在执行查询时使用的额外步骤或者特性。有Using filesort、Using temporary 的一定需要优化,根据rows可以直观看出优化结果。
1 | using index:查询时不需要回表查询,直接通过索引就可以获取查询的数据。利用覆盖索引,无需回表即可取得结果数据,这种结果是好的。 |
覆盖索引(Covering Index),一说为索引覆盖。
1 | 理解方式一:select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说**查询列要被所建的索引覆盖**。 |
注意:如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *
,因为若将所有字段一起做索引会导致索引文件过大,查询性能下降。
例子
1 | 执行顺序1: |
通过explain优化
索引失效,口诀:
简化:带头大哥不能少,中间兄弟不能断,索引列上少计算,范围之后全失效,百分like加右边,字符串里有引号。
解释:带头大哥不能少(第一字段,只要用了,不是非得它开头),中间兄弟不能断(断了索引只能用到前面的,后面用不上影响精确度,key_len和ref少了),索引列上少计算(动了容易索引失效,性能降低),范围之后全失效(索引用到范围字段为止,后面用不上索引),百分like加右边(若like '%字符%'必须用,则用覆盖索引解决),字符串里有引号(比如varchar类型,查询必须加单引号,如name=‘XXX’,否者索引失效)
单表分析:
range类型查询字段后面的索引无效,出现using filesort->删除索引,重建索引(将>
的字段去掉`)===中间兄弟没有断,索引字段可以跨where和order by使用。???
category_id = 1
可以利用索引快速定位,同时 ORDER BY views DESC
也可以利用索引的顺序,避免了文件排序(Using filesort
消失),提高了查询效率。
双表分析:
其实将class和book对调一下位置查询也是可以的,不用再删除
三表分析:
LEFT JOIN
中,驱动表通常是左边的表,尽管优化器可以调整连接顺序以提高性能,但在 LEFT JOIN
中,左表通常会被选为驱动表,因为必须保证左表的所有行都被保留。
建立索引:
- 连接条件列 :通常,应该在两个表的连接条件列上设置索引。对于左表,如果连接列上有过滤条件,索引会更有帮助。对于右表,索引可以加速匹配过程。
- 查询过滤条件列 :如果查询中有针对某个表的过滤条件,那么在该表的相应列上设置索引可以提高过滤效率。
- 覆盖查询索引 :理想情况下,索引应该覆盖查询中所有使用的列(即索引包含查询中涉及的所有列),以避免回表操作,提高查询性能。
1 | 后2行的type都是ref且总rows优化很好,效果不错。因此索引最好设置在需要经常查询的字段中。 |
查询优化(where)
注意:
1.尽量的扩展索引,不要新建索引
1 | 例如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。 |
2.最左前缀匹配原则
1 | mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配。 |
3.=和in可以乱序
1 | 比如建立(a,b,c)索引,where后a = 1 and b = 2 and c = 3 可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。 |
4.索引列排序
1 | MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。 |
5.尽量选择区分度高的列作为索引
1 | 区分度的公式是count(distinct col)/count(*),表示字段中数据不重复的比例,比例越大扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0 |
一般需要join的字段都要求是0.1以上,即平均1条扫描10条记录。
6.OR和AND
1 | OR条件的联合(union),AND条件的相交(intersection),两种情况的联合及相交,做联合操作时(通常是 or),通常耗费CPU、内存资源。 |
7.使用短索引
1 | 对字符串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和提高了索引的缓存效率,从而间接减少了磁盘 I/O 操作的次数。 |
短索引创建:
1 | CREATE INDEX idx_city ON table_name (city(3)); |
参考:https://blog.csdn.net/qq_22238021/article/details/80922166
实操:
1 | type: ref 表明使用了非唯一索引进行查找。 |
1 | 分析第一条sql:where过滤用到了c1,order by 利用索引排序c2、c3直接获得,避免了using filesort文件排序。where中的c5需要回表查询。即最终用到了c1。 |
1 | 分析第一条sql:where过滤用到了c1、c2,order by 用的是c3、c2不符合索引顺序,但由于c2已经被过滤使用,所以order by只需要排序c3,符合索引顺序,无需回表查询排序,避开了using filesort文件排序。where中的c5需要回表查询。即最终用到了c1、c2。 |
where a=3 and b like ‘kk%’ and c=4
like 后面是常量+%,虽是范围,但可落地,后面索引不失效
一般性建议
查询优化(order by)
若where未使用索引,order by使用了索引,有可能出现索引合并吗?
答:这种情况下不会出现索引合并,因为 WHERE
子句没有利用索引,说明它没有从索引中获取到数据行的过滤信息。而 ORDER BY
子句只是使用索引来对结果进行排序,并没有参与到行的过滤过程中。索引合并主要是为了优化行的过滤过程,提高 WHERE
子句的查询效率。在这种情况下,行的过滤是通过全表扫描等方式来进行的,没有出现多个不同索引用于过滤行的情况,所以不会发生索引合并。
where没有利用到索引,而order by利用到索引。这种情况也是有意义的,虽然需要回表查询数据,但索引排序可以减少排序的时间,避开了文件排序(filesort)。
order by多个字段,有索引会使用索引排序,但其中任何一个字段没有索引,就会利用filesort进行辅助排序,会有额外的IO开销和内存开销。filesort目前有两种排序算法,双路排序和单路排序。
双路排序与单路排序
1 | 双路排序查询数据时,只是将排序字段和记录ID加载到内存中,排好序后再根据id回表加载数据。 |
**ORDER BY
多字段排序时,索引失效的主因是:
- 字段顺序不匹配,
ORDER BY
后的字段顺序与复合索引的字段顺序不一致。比如索引abc,而order by b,c,a,顺序不一致,导致索引失效。 - 排序方向不匹配,
ORDER BY
后的字段的排序方向与复合索引定义的排序方向不一致。比如索引a asc,b asc,而order by a desc,b asc。
在建立复合索引时,可以建立一个一升序一降序的复合索引,通常不建议(会导致存储和维护更加复杂),而是使用默认排序(通常是升序)。
1 | CREATE INDEX idx_example ON table_name (column1 ASC, column2 DESC); |
1 | 分析: |
提高Order By的速度
小总结
1 | MySQL两种排序方式:文件排序、扫描有序索引排序 |
查询优化(group by)
无法使用索引时,group by 使用两种策略来完成:临时表或者文件排序。
可以使用索引时,where和group在索引上的联系,类似于where和order by在索引上的联系,文件排序的预知相对类似(只要符合索引字段顺序),但在临时表上,相对难以预知,情况更复杂。
1 | HAVING子句通常用于对分组后的结果再处理(在分组后的结果基础上过滤),where高于having,能写在where限定的条件就不要去having限定。 |
临时表产生的原因:
1 | 1.索引覆盖和顺序 |
group by实质是先排序后进行分组(在MySQL的早期版本是这样,但从MySQL 8.0开始,GROUP BY 语句不会在分组前先进行排序,默认也不再包含隐式排序。),遵照索引的最佳左前缀。这里的“排序”指 GROUP BY
操作本身的内部排序。
查询截取分析
1 | 1.观察,至少跑1天,看看生产的慢SQL情况。 |
总结
1.慢查询的开启并捕获
2.explain + 慢SQL分析
3.show profile查询SQL在MySQL服务器里面的执行细节和生命周期情况
4.SQL数据库服务器的参数调优。
Show profile :
是mysql 提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于sql 调优的测量。默认情况下,参数处于关闭状态,并保存最近15次的运行结果
慢查询日志
用select sleep(4)命令,模拟超过超过3s的慢sql
mysqld配置:
1 | slow_query_log=1 |
日志分析工具mysqldumpslow
1 | >mysqldumpslow --help |
mysqldumpslow的帮助信息
1 | s:是表示按照何种凡=方式排序 |
批量数据脚本
插入数据1000万条,为防止压坏,每次插入50w条数据
建表插入数据后会报错,解决办法
1、随机产生字符串
substring(字符串,开始位置,长度)截取字符串
concat(str,str)字符串连接,如果有任何一个参数为null,则返回值为null
concat(str1, seperator,str2,seperator,…)返回结果为连接参数产生的字符串并且有分隔符,如果有任何一个参数为null,则返回值为null
2、随机产生部门编号
3、创建存储过程
emp表中插入数据insert_emp(开始编号,插入条数)
删除
1 | delimiter; |
drop procedure insert_em;
dept表中插入数据
4、调用存储过程
插入10个部门
Show Profile
1、查看是否支持
1 | >Show variables like 'profiling'; |
2、开启功能
1 | >set profiling=on; |
3、运行sql
4、查看结果
1 | >show profile |
5、诊断sql
1 | >show profile cpu,block io for query |
全局查询日志
只能在测试环境用,不可用于生产
配置启用
编码启用
子查询和JOIN如何选择
每join一个表就嵌套一层循环,但总体上是只查询了一次。而子查询,每多一个子查询,则会多一次查询。
MySQL中的子查询和JOIN查询在性能上有所不同,具体取决于数据量和查询的类型。以下是关于这两种查询方式的详细讨论:
JOIN查询:
- 优点:JOIN查询可以将多个表的数据通过关联条件联合起来,一次性处理多个表的记录,提高了查询效率。
- 缺点:如果在JOIN查询中使用的连接条件不当,可能会导致查询结果出错。另外,由于需要连接多个表,因此对于连接的表数量的上限有所限制,超过这个数量后,查询性能可能会降低。
子查询:
- 优点:子查询能够在一个查询中嵌套另一个查询,实现更为复杂的查询逻辑。
- 缺点:子查询会导致查询过程变得更复杂,因为它们通常在主查询执行之前就已经完成计算。如果子查询的结果集非常大,其执行速度可能相对较慢。
在某些情况下,如数据量较小(例如1000条数据),使用JOIN查询的时间会更短,而在数据量较大的情况下(例如1000000条数据),使用IN子查询的性能会更好。
例如:
1 | SELECT name, department_id |
然而,如果子查询的结果集过大,可能导致SQL语句过长,甚至无法执行。此外,如果存在分页需求,IN子查询也无法满足。
综上所述,JOIN查询在大多数情况下是更好的选择,尤其是在处理大量数据时。但是,如果子查询的结果集很小且不需要分页,那么子查询也是一个有效的解决方案。在实际应用中,应根据具体的业务需求和数据量来选择最合适的方法。
可参考:
https://blog.51cto.com/u_16099232/6712681
https://www.shence123.com/s/23262.html
子查询可以分页吗?
子查询(Subquery)本身可以用于实现分页功能,但是它们并不总是分页查询的最佳选择。
1 | SELECT * FROM ( |
外层查询的 LIMIT 10
表示要获取10条记录,OFFSET 90
表示从内部查询结果的第91条记录开始获取。
分析:
子查询可能遇到以下问题:
- 性能问题:如果内部查询返回了大量的数据,这可能会导致性能问题,因为数据库需要先处理内部查询的所有数据,然后再由外部查询进行分页。
- 资源消耗:子查询可能会消耗更多的服务器资源,尤其是当处理大量数据时。
- 复杂性:在某些情况下,子查询可能会使 SQL 语句变得更加复杂,难以理解和维护。
- 限制:在某些数据库系统中,子查询的使用可能受到限制,或者在性能上不如直接使用
LIMIT
和OFFSET
。
通常建议:
- 直接使用
LIMIT
和OFFSET
:这是最简单直接的方法,适用于大多数情况。 - 使用行号:在一些数据库系统中,可以使用行号(如 MySQL 的
ROW_NUMBER()
函数)来实现分页,这通常比使用OFFSET
更高效。 - 索引:确保用于排序和分页的列上有适当的索引,以提高查询性能。
如何将Mysql2个性质相同的表的数据做排序分页
1 | 1. 使用 UNION ALL 合并两个表的数据 |