| # 创建数据库 |
| CREATE DATABASE atguigudb2; |
| |
| USE atguigudb2; |
| |
| # 创建表 |
| CREATE TABLE `class` ( |
| `id` INT(11) NOT NULL AUTO_INCREMENT, |
| `className` VARCHAR(30) DEFAULT NULL, |
| `address` VARCHAR(40) DEFAULT NULL, |
| `monitor` INT NULL , |
| PRIMARY KEY (`id`) |
| ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; |
| |
| # 创建表 |
| CREATE TABLE `student` ( |
| `id` INT(11) NOT NULL AUTO_INCREMENT, |
| `stuno` INT NOT NULL , |
| `name` VARCHAR(20) DEFAULT NULL, |
| `age` INT(3) DEFAULT NULL, |
| `classId` INT(11) DEFAULT NULL, |
| PRIMARY KEY (`id`) |
| #CONSTRAINT `fk_class_id` FOREIGN KEY (`classId`) REFERENCES `t_class` (`id`) |
| ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; |
| |
| # 允许创建存储函数 |
| SET GLOBAL log_bin_trust_function_creators=1; |
| |
| # 创建存储函数,随机产生字符串 |
| DELIMITER // |
| CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) |
| BEGIN |
| DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; |
| DECLARE return_str VARCHAR(255) DEFAULT ''; |
| DECLARE i INT DEFAULT 0; |
| WHILE i < n DO |
| SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); |
| SET i = i + 1; |
| END WHILE; |
| RETURN return_str; |
| END // |
| DELIMITER ; |
| |
| # 创建存储函数,用于随机产生多少到多少的编号 |
| DELIMITER // |
| CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11) |
| BEGIN |
| DECLARE i INT DEFAULT 0; |
| SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ; |
| RETURN i; |
| END // |
| DELIMITER ; |
| |
| # 创建往stu表中插入数据的存储过程 |
| DELIMITER // |
| CREATE PROCEDURE insert_stu( START INT , max_num INT ) |
| BEGIN |
| DECLARE i INT DEFAULT 0; |
| SET autocommit = 0; #设置手动提交事务 |
| REPEAT #循环 |
| SET i = i + 1; #赋值 |
| INSERT INTO student (stuno, NAME ,age ,classId ) VALUES ((START+i),rand_string(6),rand_num(1,50),rand_num(1,1000)); |
| UNTIL i = max_num |
| END REPEAT; |
| COMMIT; #提交事务 |
| END // |
| DELIMITER ; |
| |
| # 创建存储过程,往class表添加随机数据 |
| DELIMITER // |
| CREATE PROCEDURE `insert_class`( max_num INT ) |
| BEGIN |
| DECLARE i INT DEFAULT 0; |
| SET autocommit = 0; |
| REPEAT |
| SET i = i + 1; |
| INSERT INTO class ( classname,address,monitor ) VALUES (rand_string(8),rand_string(10),rand_num(1,100000)); |
| UNTIL i = max_num |
| END REPEAT; |
| COMMIT; |
| END // |
| DELIMITER ; |
| |
| # 执行存储过程,往class表添加1万条数据 |
| CALL insert_class(10000); |
| |
| # 执行存储过程,往stu表添加50万条数据 |
| CALL insert_stu(100000,500000); |
| |
| # 查看数据是否添加成功 |
| SELECT COUNT(*) FROM class; |
| |
| SELECT COUNT(*) FROM student; |
| |
| # 创建存储函数,删除表中的所有索引 |
| DELIMITER // |
| CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200)) |
| BEGIN |
| DECLARE done INT DEFAULT 0; |
| DECLARE ct INT DEFAULT 0; |
| DECLARE _index VARCHAR(200) DEFAULT ''; |
| DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY' ; |
| #每个游标必须使用不同的declare continue handler for not found set done=1来控制游标的结束 |
| DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=2 ; |
| #若没有数据返回,程序继续,并将变量done设为2 |
| OPEN _cur; |
| FETCH _cur INTO _index; |
| WHILE _index<>'' DO |
| SET @str = CONCAT("drop index " , _index , " on " , tablename ); |
| PREPARE sql_str FROM @str ; |
| EXECUTE sql_str; |
| DEALLOCATE PREPARE sql_str; |
| SET _index=''; |
| FETCH _cur INTO _index; |
| END WHILE; |
| CLOSE _cur; |
| END // |
| DELIMITER ; |
| |
| # 执行存储过程 |
| CALL proc_drop_index("dbname","tablename"); |
| # 创建索引 |
| CREATE INDEX idx_age ON student(age); |
| |
| CREATE INDEX idx_age_classid ON student(age,classId); |
| |
| CREATE INDEX idx_age_classid_name ON student(age,classId,NAME); |
| |
| # 测试 |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4 AND NAME = 'abcd'; |
| |
| SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4 AND NAME = 'abcd'; |
| # 查询从索引的最左前列开始并且不跳过索引中的列 |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.age=30 AND student.name = 'abcd' ; |
| |
| # 如果先查询id,但联合索引中是以age开始的,所以age索引就失效了 |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.classid=1 AND student.name = 'abcd'; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student |
| WHERE classid=4 AND student.age=30 AND student.name = 'abcd'; |
| |
| DROP INDEX idx_age ON student; |
| DROP INDEX idx_age_classid ON student; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student |
| WHERE student.age=30 AND student.name = 'abcd'; |
| 对于一个使用InnoDB存储引擎的表来说,在我们没有显式的创建索引时,表中的数据实际上都是存储在聚簇索引的叶子节点的。而记录又是存储 |
| 在数据页中的,数据页和记录又是按照记录主键值从小到大的顺序进行排序,所以如果我们插入的记录的主键值是依次增大的话,那我们每插满 |
| 一个数据页就换到下一个数据页继续插,而如果我们插入的主键值忽大忽小的话,效率很低,最好能让插入的记录主键依次递增 |
| # 此语句比下一条要好!(能够使用上索引) |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%'; |
| |
| # 先遍历运行函数,后比较,不能用上索引 |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name,3) = 'abc'; |
| |
| CREATE INDEX idx_name ON student(NAME); |
| |
| CREATE INDEX idx_sno ON student(stuno); |
| |
| # 先遍历计算,后比较,不能使用索引 |
| EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno+1 = 900001; |
| |
| EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno = 900000; |
| |
| # 先遍历进行类型转换,后比较,不能使用索引 |
| EXPLAIN SELECT id, stuno, NAME FROM student WHERE SUBSTRING(NAME, 1,3)='abc'; |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME = 123; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME = '123'; |
| # 查看表中索引 |
| SHOW INDEX FROM student; |
| # 清空表的索引 |
| CALL proc_drop_index('atguigudb2','student'); |
| |
| # 创建联合索引 |
| CREATE INDEX idx_age_classId_name ON student(age,classId,NAME); |
| |
| # 创建联合索引 |
| CREATE INDEX idx_age_name_cid ON student(age,NAME,classId); |
| |
| # 根据name查询时,name没有用上 |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student |
| WHERE student.age=30 AND student.classId>20 AND student.name = 'abc' ; |
| |
| # 将返回条件放到最后即可保证右边索引不会失效 |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student |
| WHERE student.age=30 AND student.name = 'abc' AND student.classId>20; |
| CREATE INDEX idx_name ON student(NAME); |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name <> 'abc' ; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name != 'abc' ; |
- is null可以使用索引,is not null无法使用索引
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NULL; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age IS NOT NULL; |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE 'ab%'; |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE '%ab%'; |
| SHOW INDEX FROM student; |
| |
| CALL proc_drop_index('atguigudb2','student'); |
| |
| CREATE INDEX idx_age ON student(age); |
| |
| EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100; |
| |
| CREATE INDEX idx_cid ON student(classid); |
- 数据库和表的字符集统一使用utf8mb4,否则类型转换时会导致索引失效
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术