专职DBA-MySQL索引及执行计划
时间:2019-07-20
本文章向大家介绍专职DBA-MySQL索引及执行计划,主要包括专职DBA-MySQL索引及执行计划使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
专职DBA-MySQL索引及执行计划 索引的作用 提供了类似于书中目录的作用,目录是为了优化查询。 索引的种类(算法) B树索引 Hash索引 R树 Full text GIS B树基于不同的查找算法分类介绍
B-tree B+Tree 在范围查询方面提供了更好的性能(> < >= <= like) B*Tree 在功能上分类 辅助索引(S)怎么构建B树结构的? (1).索引是基于表中,列(索引键)的值生成的B树结构。 (2).首先提取此列所有的值,进行自动排序。 (3).将排好序的值,均匀的分布到索引树的叶子节点中(16K). (4).然后生成此索引键值所对应得后端数据页的指针。 (5).生成枝节点和根节点,根据数据量级和索引键长度,生成合适的索引树高度。 id name age gender select * from t1 where id=10; 问题: 基于索引键做where查询,对于id列是顺序IO,但是对于其他列的查询,可能是随机IO. 聚集索引(C) 前提 (1).表中设置了主键,主键列就会自动被作为聚集索引。 (2).如果没有主键,会选择唯一键作为聚集索引。 (3).聚集索引必须在建表时才有意义,一般是表的无关列(ID). 辅助索引(S)怎么构建B树结构的? (1).在建表时,设置了主键列(ID). (2).在将来录入数据时,就会按照ID列的顺序存储到磁盘上(我们又称之为聚集索引组织表)。 (3).将排好序的整行数据,生成叶子节点,可以理解为磁盘的数据页就是叶子节点。 聚集索引和辅助索引构成区别 聚集索引只能有一个,非空唯一,一般是主键。 辅助索引,可以有多个,是配合聚集索引使用的。 聚集索引叶子节点,就是磁盘的数据行存储的数据页。 MySQL是根据聚集索引,组织存储数据,数据存储时就是按照聚集索引的顺序进行存储数据。 辅助索引,只会提取索引键值,进行自动排序生成B树结构。
辅助索引细分 1.普通的单列辅助索引。 2.联合索引。 多个列作为索引条件,生成索引树,理论上设计的好的,可以减少大量的回表查询。 3.唯一索引。 索引列的值都是唯一的。 关于索引树的高度受什么影响? 1.数据量级,解决方法:分表,分库,分布式。 2.索引列值过长,解决方法:前缀索引。 3.数据类型: 变长长度字符串,使用了char,解决方案:变长字符串使用varchar. enum类型的使用enum ('山东','河北','黑龙江','吉林','辽宁','陕西'......) 1 2 3 索引的基本管理 索引建立前 [root@db01 ~]# ps -ef|grep mysql mysql 6453 1 0 02:51 ? 00:00:02 /app/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf mysql 6454 1 0 02:51 ? 00:00:02 /app/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf mysql 6459 1 0 02:51 ? 00:00:02 /app/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf mysql 7222 1 13 03:45 ? 00:00:00 /app/mysql/bin/mysqld --defaults-file=/etc/my.cnf root 7252 6751 0 03:45 pts/0 00:00:00 grep --color=auto mysql [root@db01 ~]# mysql -uroot -p -S /tmp/mysql.sock Enter password: mysql [(none)]> desc world.city; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | NULL | auto_increment | | Name | char(35) | NO | | | | | CountryCode | char(3) | NO | MUL | | | | District | char(20) | NO | | | | | Population | int(11) | NO | | 0 | | +-------------+----------+------+-----+---------+----------------+ 5 rows in set (0.02 sec) Field : 列名字 key : 有没有索引,索引类型。 PRI : 主键索引。 UNI : 唯一索引。 MUL : 辅助索引(单列,联和,前缀) 单列普通辅助索引 创建索引 mysql [(none)]> use world; Database changed mysql [world]> alter table city add index idx_name(name); Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql [world]> create index idx_name1 on city(name); Query OK, 0 rows affected, 1 warning (0.05 sec) Records: 0 Duplicates: 0 Warnings: 1 mysql [world]> show index from city; +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | city | 0 | PRIMARY | 1 | ID | A | 4188 | NULL | NULL | | BTREE | | | | city | 1 | CountryCode | 1 | CountryCode | A | 232 | NULL | NULL | | BTREE | | | | city | 1 | idx_name | 1 | Name | A | 3998 | NULL | NULL | | BTREE | | | | city | 1 | idx_name1 | 1 | Name | A | 3998 | NULL | NULL | | BTREE | | | +-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 4 rows in set (0.00 sec)
注意: 以上操作不代表生产操作,我们不建议在一个列上建多个索引。 同一个表中,索引名不能同名。 删除索引 mysql [world]> alter table city drop index idx_name1; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql [world]> show index from city; 覆盖索引(联合索引) mysql [world]> alter table city add index idx_co_po(countrycode,population); Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0 前缀索引 mysql [world]> alter table city add index idx_di(district(5)); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 注意:数字列不能用作前缀索引。 唯一索引 mysql [world]> alter table city add unique index idx_unil(name); ERROR 1062 (23000): Duplicate entry 'San Jose' for key 'idx_unil' 统计city表中,以省的名字为分组,统计组的个数。 mysql [world]> select district,count(id) from city group by district; 需求:找到world下,city表中name列有重复值的行,最后删掉重复的行。 mysql [world]> select name,count(id) as cid from city group by name having cid>1 order by cid desc; mysql [world]> select * from city where name='suzhou'; +------+--------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+--------+-------------+----------+------------+ | 1935 | Suzhou | CHN | Jiangsu | 710000 | | 2133 | Suzhou | CHN | Anhui | 151862 | +------+--------+-------------+----------+------------+ 2 rows in set (0.00 sec) 执行计划获取及分析 介绍 (1).获取到的是优化器选择完成的,他认为代价最小的执行计划。 作用:语句执行前,先看执行计划信息,可以有效的防止性能较差的语句带来的性能问题。 如果业务中出现了慢语句,我们也需要借助此命令进行语句的评估,分析优化方案。 (2).select 获取数据的方法。 1.全表扫描(应当尽量避免,因为性能低) 2.索引扫描。 3.获取不到数据。 执行计划获取 获取优化器选择后的执行计划 开始模拟数据库数据 打开SQLyog或者Aqua插入100w行数据
模拟数据库数据 drop database if exists shenzhen; create database shenzhen charset utf8mb4 collate utf8mb4_bin; use shenzhen; create table t_100w (id int,num int,k1 char(2),k2 char(4),dt timestamp); delimiter // create procedure rand_data(in num int) begin declare str char(62) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; declare str2 char(2); declare str4 char(4); declare i int default 0; while i<num do set str2=concat(substring(str,1+floor(rand()*61),1),substring(str,1+floor(rand()*61),1)); set str4=concat(substring(str,1+floor(rand()*61),2),substring(str,1+floor(rand()*61),2)); set i=i+1; insert into t_100w values (i,floor(rand()*num),str2,str4,now()); end while; end; // delimiter; 插入100w条数据: call rand_data(1000000); commit; 固态就是快,没办法哈哈! mysql [(none)]> select count(*) from shenzhen.t_100w; +----------+ | count(*) | +----------+ | 1000000 | +----------+ 1 row in set (0.38 sec) mysql [shenzhen]> use shenzhen; Database changed mysql [shenzhen]> desc select * from t_100w where id=9000; +----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | t_100w | NULL | ALL | NULL | NULL | NULL | NULL | 997396 | 10.00 | Using where | +----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) 执行计划分析,重点关注的信息 mysql [shenzhen]> explain select * from t_100w where id=9000\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t_100w 查询的表名 partitions: NULL type: ALL 查询类型 possible_keys: NULL 可能会走的索引 key: NULL 真正走的索引名 key_len: NULL 应用索引的长度 ref: NULL rows: 997396 查询结果集的长度 filtered: 10.00 Extra: Using where 额外信息 1 row in set, 1 warning (0.00 sec) type详解 从左到右性能依次变好. ALL : 全表扫描,不走索引 例子: 1.查询条件列,没有索引 SELECT * FROM t_100w WHERE k2='780P'; 2.查询条件出现以下语句(辅助索引列) USE world; DESC city; DESC SELECT * FROM city WHERE countrycode != 'CHN'; DESC SELECT * FROM city WHERE countrycode NOT IN ('CHN','USA'); DESC SELECT * FROM city WHERE countrycode LIKE '%CH%'; 注意:对于聚集索引列,使用以上语句,依然会走索引 DESC SELECT * FROM city WHERE id != 10; INDEX : 全索引扫描 1.查询需要获取整个索引树种的值时 DESC SELECT countrycode FROM city; 2.联合索引中,任何一个非最左列作为查询条件时: idx_a_b_c(a,b,c) ---> a ab abc SELECT * FROM t1 WHERE b SELECT * FROM t1 WHERE c RANGE : 索引范围扫描 辅助索引> < >= <= LIKE IN OR 主键 != NOT IN 例子: 1.DESC SELECT * FROM city WHERE id<5; 2.DESC SELECT * FROM city WHERE countrycode LIKE 'CH%'; 3.DESC SELECT * FROM city WHERE countrycode IN ('CHN','USA'); 注意: 1和2例子中,可以享受到B+树的优势,但是3例子中是不能享受的。 所以我们可以将3号列子改写: DESC SELECT * FROM city WHERE countrycode='CHN' UNION ALL SELECT * FROM city WHERE countrycode='USA'; ref : 非唯一性索引,等值查询 DESC SELECT * FROM city WHERE countrycode='CHN'; eq_ref : 在多表连接时,连接条件使用了唯一索引(uk pK) DESC SELECT b.name,a.name FROM city AS a JOIN country AS b ON a.countrycode=b.code WHERE a.population <100; DESC country; system,const : 唯一索引的等值查询 DESC SELECT * FROM city WHERE id=10; 其他字段解释 extra: filesort 文件排序. SHOW INDEX FROM city; ALTER TABLE city ADD INDEX CountryCode(CountryCode); ALTER TABLE city DROP INDEX idx_c_p; DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population; ALTER TABLE city ADD INDEX idx_(population); DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population; ALTER TABLE city ADD INDEX idx_c_p(countrycode,population); ALTER TABLE city DROP INDEX idx_; ALTER TABLE city DROP INDEX CountryCode; DESC SELECT * FROM city WHERE countrycode='CHN' ORDER BY population; 结论: 1.当我们看到执行计划extra位置出现filesort说明由文件排序出现。 2.观察需要排序(ORDER BY,GROUP BY,DISTINCT)的条件有没有索引。 3.根据子句的执行顺序去创建联合索引。 索引优化效果测试 优化前 [root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf \ > --concurrency=100 --iterations=1 --create-schema='shenzhen' \ > --query="select * from shenzhen.t_100w where k2='ABWX'" engine=innodb \ > --number-of-queries=2000 -uroot -p123 -verbose mysqlslap: [Warning] Using a password on the command line interface can be insecure. Benchmark Running for engine rbose Average number of seconds to run all queries: 932.120 seconds Minimum number of seconds to run all queries: 932.120 seconds Maximum number of seconds to run all queries: 932.120 seconds Number of clients running queries: 100 Average number of queries per client: 20 100并发 2000次查询 优化后 mysql [shenzhen]> alter table t_100w add index idx(k2); Query OK, 0 rows affected (2.01 sec) Records: 0 Duplicates: 0 Warnings: 0 [root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf \ > --concurrency=100 --iterations=1 --create-schema='shenzhen' \ > --query="select * from shenzhen.t_100w where k2='ABWX'" engine=innodb \ > --number-of-queries=2000 -uroot -p123 -verbose mysqlslap: [Warning] Using a password on the command line interface can be insecure. Benchmark Running for engine rbose Average number of seconds to run all queries: 1.539 seconds Minimum number of seconds to run all queries: 1.539 seconds Maximum number of seconds to run all queries: 1.539 seconds Number of clients running queries: 100 Average number of queries per client: 20 体验到效果了吗!!! 联合索引: 1.SELECT * FROM t1 WHERE a= b= 我们建立联合索引时: ALTER TABLE t1 ADD INDEX idx_a_b(a,b); ALTER TABLE t1 ADD INDEX idx_b_a(b,a); 以上的查询不考虑索引的顺序,优化器会自动调整where的条件顺序 注意: 索引,我们在这种情况下建索引时,需要考虑哪个列的唯一值更多,哪个放在索引左边。 2.如果出现where条件中出现不等值查询条件 DESC SELECT * FROM t_100w WHERE num <1000 AND k2='DEEF'; 我们建索引时: ALTER TABLE t_100w ADD INDEX idx_2_n(k2,num); 语句书写时: DESC SELECT * FROM t_100w WHERE k2='DEEF' AND num <1000; 3.如果查询中出现多子句 我们要按照子句的执行顺序进行建立索引。 explain (desc) 使用场景(面试题) 题目意思:我们公司业务慢,请你从数据库的角度分析原因。 mysql出现性能问题,我总结有两种情况: 1.应急性的慢:突然夯住 应急情况:数据库hang(卡了,资源耗尽) 处理过程: (1).show processlist;获取到导致数据库hang的语句。 (2).explain分析SQL的执行计划,有没有走索引,索引的类型情况。 (3).建索引,改语句。 2.一段时间慢(持续性的): (1)记录慢日志slowlog,分析slowlog. (2)explain分析SQL的执行计划,有没有走索引,索引的类型情况。 (3)建索引,改语句。 索引应用规范 什么是业务??? 1.产品的功能 2.用户的行为 "热"查询语句--->较慢--->slowlog "热"数据 建立索引的原则(DBA运维规范) 说明 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引。那么索引设计原则又是怎样的? (必须的)建表时一定要有主键,一般是个无关列。 略,回顾一下,聚集索引结构。 选择唯一性索引 唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。 例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。 如果使用姓名的话,可能存在同名现象,从而降低查询速度。 优化方案: (1).如果非得使用重复值较多的列作为查询条件(例如:男女)可以将表逻辑拆分。 (2).可以将此列和其他的查询类,做联和索引。 select count(*) from world.city; select count(distinct countrycode) from world.city; select count(distinct countrycode,population ) from world.city; (必须的)为经常需要where、ORDER BY、GROUP BY、join on等操作字段。 排序操作会浪费很多时间。 where A B C ----》 A B C in where A group by B order by C A,B,C 如果为其建立索引,优化查询。 注:如果经常作为条件的列,重复值特别多,可以建立联合索引。 尽量使用前缀来索引 如果索引字段的值很长,最好使用值的前缀来索引。 限制索引的数目 索引的数目不是越多越好。 可能会产生的问题: (1).每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。 (2).修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。 (3).优化器的负担会很重,有可能会影响到优化器的选择。 percona-toolkit中有个工具,专门分析索引是否有用。 删除不再使用或者很少使用的索引(percona toolkit) pt-duplicate-key-checker 表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。 大表加索引,要在业务不繁忙期间操作。 尽量少在经常更新值的列上建索引。 建索引原则 (1).必须要有主键,如果没有可以做为主键条件的列,创建无关列。 (2).经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)。 (3).最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引 (4).列值长度较长的索引列,我们建议使用前缀索引。 (5).降低索引条目,一方面不要创建没用索引,不常使用的索引清理percona toolkit(xxxxx)。 (6).索引维护要避开业务繁忙期。 不走索引的情况(开发规范): 没有查询条件,或者查询条件没有建立索引 select * from tab; 全表扫描 select * from tab where 1=1; 在业务数据库中,特别是数据量比较大的表。 是没有全表扫描这种需求。 1.对用户查看是非常痛苦的。 2.对服务器来讲毁灭性的。 select * from tab; SQL改写成以下语句: (1)select * from tab order by price limit 10;需要在price列上建立索引 (2)select * from tab where name='zhangsan'; name列没有索引 改: 1.换成有索引的列作为查询条件。 2.将name列建立索引。 查询结果集是原表中的大部分数据,应该是25%以上。 查询的结果集,超过了总数行数25%,优化器觉得就没有必要走索引了。 假如:tab表 id,name id:1-100w id列有(辅助)索引 select * from tab where id>500000; 如果业务允许,可以使用limit控制。 怎么改写? 结合业务判断,有没有更好的方式,如果没有更好的改写方案。 尽量不要在mysql存放这个数据了,放到redis里面。 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+ - * / !等) 例子: 错误的例子:select * from test where id-1=9; 正确的例子:select * from test where id=10; 算术运算 函数运算 子查询 隐式转换导致索引失效。这一点应当引起重视,也是开发中经常会犯的错误。 这样会导致索引失效. 错误的例子: mysql> alter table tab add index inx_tel(telnum); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc tab; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | telnum | varchar(20) | YES | MUL | NULL | | +--------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec) mysql> select * from tab where telnum='1333333'; +------+------+---------+ | id | name | telnum | +------+------+---------+ | 1 | a | 1333333 | +------+------+---------+ 1 row in set (0.00 sec) mysql> select * from tab where telnum=1333333; +------+------+---------+ | id | name | telnum | +------+------+---------+ | 1 | a | 1333333 | +------+------+---------+ 1 row in set (0.00 sec) mysql> explain select * from tab where telnum='1333333'; +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ | 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition | +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ 1 row in set (0.00 sec) mysql> explain select * from tab where telnum=1333333; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from tab where telnum=1555555; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from tab where telnum='1555555'; +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ | 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition | +----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ 1 row in set (0.00 sec) != not in 不走索引(辅助索引) EXPLAIN SELECT * FROM teltab WHERE telnum != '110'; EXPLAIN SELECT * FROM teltab WHERE telnum NOT IN ('110','119'); mysql> select * from tab where telnum != '1555555'; +------+------+---------+ | id | name | telnum | +------+------+---------+ | 1 | a | 1333333 | +------+------+---------+ 1 row in set (0.00 sec) mysql> explain select * from tab where telnum != '1555555'; 单独的>,<,in 有可能走,也有可能不走,和结果集有关,尽量结合业务添加limit or或in 尽量改成union EXPLAIN SELECT * FROM teltab WHERE telnum IN ('110','119'); 改写成: EXPLAIN SELECT * FROM teltab WHERE telnum='110' UNION ALL SELECT * FROM teltab WHERE telnum='119'; like "%_" 百分号在最前面不走。 走range索引扫描 explain select * from teltab where telnum like '31%'; 不走索引 explain select * from teltab where telnum like '%110'; %linux%类的搜索需求,可以使用elasticsearch+mongodb专门做搜索服务的数据库产品。
原文地址:https://www.cnblogs.com/zhouwanchun/p/11217788.html
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- SpringBoot微服务架构项目--Union社交平台
- 如何衡量前端基建的效能价值?
- mbedtls | 移植mbedtls库到STM32裸机的两种方法
- 实用小技巧 | 用socket玩转http接口
- 深度学习之人脸识别模型--FaceNet
- Java常用的设计模式
- HW防守|应急溯源分析手册汇总篇
- Python进阶(一)
- Python版本的OpenCV安装
- CVE-2020-16875:Microsoft Exchange RCE复现
- 抢先学鸿蒙(HarmonyOS)2.0,你就是下一个大咖!
- Python高效编程之88条军规(2):你真的会格式化字符串吗?
- 搭建Typecho博客
- Python开发之Pandas的使用
- Python开发之numpy的使用