mysql千万级数据量根据索引优化查询速度

本文深入解析MySQL中的索引原理及应用,包括主键索引、普通索引和聚合索引的作用与创建方法,并通过实测展示索引如何显著提升查询速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)索引的作用

索引通俗来讲就相当于书的目录,当我们根据条件查询的时候,没有索引,便需要全表扫描,数据量少还可以,一旦数据量超过百万甚至千万,一条查询sql执行往往需要几十秒甚至更多,5秒以上就已经让人难以忍受了。

提升查询速度的方向一是提升硬件(内存、cpu、硬盘),二是在软件上优化(加索引、优化sql;优化sql不在本文阐述范围之内)。

能在软件上解决的,就不在硬件上解决,毕竟硬件提升代码昂贵,性价比太低。代价小且行之有效的解决方法就是合理的加索引。

索引使用得当,能使查询速度提升上万倍,效果惊人。

(二)mysql的索引类型:

mysql的索引有5种:主键索引、普通索引、唯一索引、全文索引、聚合索引(多列索引)。

唯一索引和全文索引用的很少,我们主要关注主键索引、普通索引和聚合索引。

1)主键索引:主键索引是加在主键上的索引,设置主键(primary key)的时候,mysql会自动创建主键索引;

2)普通索引:创建在非主键列上的索引;

3)聚合索引:创建在多列上的索引。

(三)索引的语法:

查看某张表的索引:show index from 表名;

创建普通索引:alter table 表名 add index  索引名 (加索引的列) 

创建聚合索引:alter table 表名 add index  索引名 (加索引的列1,加索引的列2) 

删除某张表的索引:drop index 索引名 on 表名;

(四)性能测试

测试环境:博主工作用台式机

处理器为Intel Core i5-4460 3.2GHz;

内存8G;

64位windows。

1:创建一张测试表

 

DROP TABLE IF EXISTS `test_user`;
CREATE TABLE `test_user` (
  `id` bigint(20)  PRIMARY key not null AUTO_INCREMENT,
  `username` varchar(11) DEFAULT NULL,
  `gender` varchar(2) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
存储引擎使用MyISAM是因为此引擎没有事务,插入速度极快,方便我们快速插入千万条测试数据,等我们插完数据,再把存储类型修改为InnoDB。

 

2:使用存储过程插入1千万条数据

 

create procedure myproc() 
begin 
declare num int; 
set num=1; 
while num <= 10000000 do 
insert into test_user(username,gender,password) values(num,'保密',PASSWORD(num)); 
set num=num+1;
end while;
 end
call myproc();
由于使用的MyISAM引擎,插入1千万条数据,仅耗时246秒,若是InnoDB引擎,插入100万条数据就要花费数小时了。

 

然后将存储引擎修改回InnDB。使用如下命令:  alter table test_user engine=InnoDB;此命令执行时间大约耗时5分钟,耐心等待。

tips:这里是测试,生产环境中不要随意修改存储引擎,还有alter table 操作,会锁整张表,慎用。其次:myisam引擎没有事务,且只是将数据写到内存中,然后定期将数据刷出到磁盘上,因此突然断电的情况下,会导致数据丢失。而InnDB引擎,是将数据写入日志中,然后定期刷出到磁盘上,所以不怕突然断电等情况。因此在实际生产中能用InnDB则用。

3:sql测试

select id,username,gender,password from test_user where id=999999

耗时:0.114s。

因为我们建表的时候,将id设成了主键,所以执行此sql的时候,走了主键索引,查询速度才会如此之快。

 

我们再执行select id,username,gender,password from test_user where username='9000000'
耗时:4.613s。

 

我们给username列加上普通索引。

ALTER TABLE `test_user` ADD INDEX index_name(username) ;

此过程大约耗时 54.028s,建索引的过程会全表扫描,逐条建索引,当然慢了。

再来执行:selectid,username,gender,password from test_user where username='9000000'
耗时:0.043s。

 

再用username和password来联合查询

select id,username,gender,password  from test_user where username='9000000' and `password`='*3A70E147E88D99888804E4D472410EFD9CD890AE'

此时虽然我们队username加了索引,但是password列未加索引,索引执行password筛选的时候,还是会全表扫描,因此此时

查询速度立马降了下来。

耗时:4.492s。

 

当我们的sql有多个列的筛选条件的时候,就需要对查询的多个列都加索引组成聚合索引:

加上聚合索引:ALTER TABLE `test_user` ADD INDEX index_union_name_password(username,password)
再来执行:

耗时:0.001s。

 

开篇也说过软件层面的优化一是合理加索引;二是优化执行慢的sql。此二者相辅相成,缺一不可,如果加了索引,还是查询很慢,这时候就要考虑是sql的问题了,优化sql。

实际生产中的sql往往比较复杂,如果数据量过了百万,加了索引后效果还是不理想,使用集群。

 

Tips:

1:加了索引,依然全表扫描的可能情况有:

索引列为字符串,而没带引号;

索引列没出现在where条件后面;

索引列出现的位置没在前面。

2:关联查询不走索引的可能情况有:

关联的多张表的字符集不一样;

关联的字段的字符集不一样;

存储引擎不一样;

字段的长度不一样。


--------------------- 
转自:https://blog.youkuaiyun.com/qq_33556185/article/details/52192551 
 

### TDSQL for MySQL千万级数据量下的性能优化技巧 针对 TDSQL for MySQL 在处理千万级数据量时的性能问题,可以从以下几个方面入手进行优化。以下是详细的优化建议: #### 1. SQL 执行计划优化 确保查询语句具有高效的执行计划是非常重要的一步。可以通过 `EXPLAIN` 工具查看具体的执行计划,并根据返回的信息调整查询逻辑或索引结构[^1]。如果发现全表扫描的情况较多,则应该重新审视现有索引的设计是否合理。 ```sql -- 查看SQL执行计划示例 EXPLAIN SELECT * FROM user_data WHERE age > 30 AND city='Beijing'; ``` #### 2. 合理创建与维护索引 虽然建立更多的索引可以帮助快某些类型的检索操作速度,但是过多或者不当使用的索引也会拖累更新、删除等DML语句的速度,甚至占用额外存储空间。因此,在决定为某个字段索引前要综合考量该字段在各种典型查询中的重要程度以及它本身的数据分布特性等因素[^1]。 对于那些经常出现在WHERE子句里的列优先考虑设立单独或是组合形式上的普通B树型索引;而对于范围查找较为常见的场景则更适合采用覆盖索引来减少回源频率从而提升整体表现水平[^3]。 #### 3. 数据分区技术的应用 随着数据规模的增长,单一物理表可能变得难以管理和高效访问。此时可以引入数据分区的概念——按照一定规则将原始大表拆分成若干个小区域分别存放在不同的磁盘位置上。如此一来不仅便于后续管理还能有效改善特定模式下读写效率低下状况的发生概率[^4]。 例如按日期维度划分用户行为日志类别的大数据集合就是一个很典型的例子之一: ```sql CREATE TABLE log_partitioned ( id INT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, message TEXT ) PARTITION BY RANGE (YEAR(created_at)) ( PARTITION p0 VALUES LESS THAN (2020), PARTITION p1 VALUES LESS THAN (2021), PARTITION p2 VALUES LESS THAN MAXVALUE ); ``` #### 4. 系统参数微调 适当修改一些mysqld服务端全局变量值也能起到不错的效果。像innodb_buffer_pool_size决定了InnoDB引擎缓存区内存量大小,默认情况下仅占服务器总RAM容量的一半左右,但对于专用数据库实例而言完全可以将其设得更大些以便容纳更多热数据页面到内存当中去直接命中而不必每次都从硬盘上调取副本[^1]。 另外诸如max_connections,max_heap_table_size,tmp_table_size之类也会影响并发连接数上限及临时对象最大尺寸限制等方面的表现特征故而也需要依据实际情况做出相应调整。 --- ### 提供一段关于如何判断是否存在锁冲突导致性能下降的例子程序片段 有时候即使做了以上种种努力仍然无法彻底解决问题根源或许隐藏于深层次内部机制之中比如说隐秘存在的死锁现象等等。下面给出了一段简单脚本用来检测是否有长期未释放的行级排他性锁定存在: ```sql SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; ``` 通过定期监控此类指标变化趋势有助于及时发现问题苗头采取预防措施避免事态进一步恶化扩散开来影响正常业务运转秩序。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值