MySql 使用索引进行查询优化;常用mysql优化

MySQL LEFT JOIN 性能优化策略 我们现在有一个驱动表customer,它存储客户id、姓名以及出生日期,默认情况下idcustomer有一张关联表,c_id记录着与其关联数据的id,并用记录客户余额,对应DDL假设此时数据库大约有2000w的数据,我们希望查出姓名为的用户的出生日期和可用余额,如果没有记录余额则设置为null,对应我们给出这样一条SQL最终查询结果如下,耗时大约是1s多一些,对于用户而言超过200ms。 阅读详情
AI摘要

本文介绍了MySQL中索引的工作原理及优化策略,包括如何选择有效的索引、避免索引失效的场景、以及如何通过索引提升查询性能。还讨论了在不同场景下使用索引的最佳实践。

索引有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。

建索引的几大原则

1、最左前缀匹配原则,非常重要的原则

对于多列索引,总是从索引的最前面字段开始,接着往后,中间不能跳过。比如创建了多列索引(name,age,sex),会先匹配name字段,再匹配age字段,再匹配sex字段的,中间不能跳过。mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配。比如a = 1 and b = 2 and c > 3 and d = 4,如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

2、尽量选择区分度高的列作为索引

区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。(比如,我们会选择学号做索引,而不会选择性别来做索引。)

3、=和in可以乱序

比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

4、索引列不能参与计算,保持列“干净”

比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);

例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<'2007-01-01'。

比如:Flistid+1>‘2000000608201108010831508721‘。原因很简单,假如索引列参与计算的话,那每次检索时,都会先将索引计算一次,再做比较,显然成本太大。

5、尽量的扩展索引,不要新建索引

比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

6. 索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

7. 使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

8. 索引列排序

MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

9. like语句操作

一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

最后总结一下,MySQL只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的,比如我刚才针对text类型的字段创建索引的时候,系统差点就卡死了。

使用索引优化查询

使用索引的典型场景

1、匹配全值

对索引中所有列都指定具体值,即对索引中的所有列都有等值匹配的条件。

#设置组合索引(rental_date,inventory_id,customer_id)为唯一索引。
EXPLAIN 
SELECT 
  * 
FROM
  rental 
WHERE rental_date = '2005-05-25 17:22:10' 
  AND inventory_id = 373 
  AND customer_id = 343 ;

这里写图片描述

2、匹配值的范围查询

对索引的值能够进行范围查找。

#设置索引idx_fk_customer_id(customer_id)
EXPLAIN 
SELECT 
  * 
FROM
  rental 
WHERE customer_id >= 373 
  AND customer_id < 400 ;

这里写图片描述

类型type为range说明优化器选择范围查询,索引key为idx_fk_customer_id说明优化器选择索引idx_fk_customer_id来加速访问,Extra为using where说明优化器除了利用索引加速访问外,还需要根据索引回表查询数据。

3、匹配最左前缀

仅仅使用索引中的最左边列进行查询。比如组合索引(col1,col2,col3)能够被col1,col1+col2,col1+col2+col3的等值查询利用到的。

#创建索引idx_payment_date(payment_date,amount,last_update);
EXPLAIN 
SELECT 
  * 
FROM
  payment 
WHERE payment_date = '2006-02-14 15:16:03' 
  AND last_update = '2006-02-15 22:12:32' ;

这里写图片描述

从结果可以看出利用了索引,但又row为182行,所有只使用了部分索引。

EXPLAIN 
SELECT 
  * 
FROM
  payment 
WHERE amount = 3.98 
  AND last_update = '2006-02-15' ;

这里写图片描述

从结果看出,这次查询没有利用索引,进行了全表查找。

4、仅对索引进行查询

当查询列都在索引字段中。即select中的列都在索引中。

EXPLAIN 
SELECT 
  last_update 
FROM
  payment 
WHERE payment_date = '2005-08-19 21:21:47' 
  AND amount = 4.99 ;

这里写图片描述

extra部分Using index,说明不需要通过索引回表,Using index就是平时说的覆盖索引扫描(即找到索引,就找到了要查询的结果,不用再回表查找了)。

5、匹配列前缀

仅仅使用索引的第一列,并且只包含索引第1列的开头部分进行查找。

#创建索引idx_title_desc_part(title(10),description(20));
EXPLAIN 
SELECT 
  title 
FROM
  film_text 
WHERE title LIKE 'AFRICAN%' ;

这里写图片描述

6、索引部分等值匹配,部分范围匹配
EXPLAIN 
SELECT 
  inventory_id 
FROM
  rental 
WHERE rental_date = '2006-02-14 15:16:03' 
  AND customer_id >= 300 
  AND customer_id <= 400 ;

这里写图片描述

type=ref,说明使用了索引。key为idx_rental_date说明优化器选择使用索引加速查询,同时由于只查询索引字段inventory_id,故Extra部分有using index,表示查询使用了覆盖索引扫描。

7、若列名是索引,则使用column_name is null就会使用索引
EXPLAIN 
SELECT 
  * 
FROM
  payment 
WHERE rental_id IS NULL ;

这里写图片描述

索引存在但不能使用索引的典型场景

1、以%开头的like查询
EXPLAIN 
SELECT 
  * 
FROM
  actor 
WHERE last_name LIKE '%NI%' ;

这里写图片描述

因为B-Tree索引的结构,所以以%开头的查询自然没法使用索引。InnoDB的表都是聚簇表,一般索引都会比表小,扫描索引比扫描表更快,而InnoDB表上二级索引idx_last_name实际上存储字段last_name和主键actor_id,故先扫描二级索引idx_last_name获得满足条件last_name like '%NI%'的主键actor_id列表,之后根据主键回表去检索记录,这样避免了全表扫面演员表actor产生的大量IO请求

#优化
EXPLAIN 
SELECT 
  * 
FROM
  (SELECT 
    actor_id 
  FROM
    actor 
  WHERE last_name LIKE '%NI%') a,
  actor b 
WHERE a.actor_id = b.actor_id ;

这里写图片描述

2、数据类型出现隐式转化,不会使用索引
EXPLAIN 
SELECT 
  * 
FROM
  actor 
WHERE last_name = 1 ;

这里写图片描述

#使用索引
EXPLAIN 
SELECT 
  * 
FROM
  actor 
WHERE last_name = '1' ;

这里写图片描述

3、组合索引,不满足最左原则,不使用符合索引
EXPLAIN 
SELECT 
  * 
FROM
  payment 
WHERE amount = 3.98 
  AND last_update = '2006-02-15 22:12:32' ;

这里写图片描述

4、估计使用索引比全表扫描还慢,则不要使用索引

update film_text set title=concat('S',title);

如查询以“S”开头的标题的电影,返回记录比例比较大,mysql预估索引扫描还不如全表扫描。

EXPLAIN 
SELECT 
  * 
FROM
  film_text 
WHERE title LIKE 'S%' ;

这里写图片描述

5、用or分割条件,若or前后只要有一个列没有索引,就都不会用索引
EXPLAIN 
SELECT 
  * 
FROM
  payment 
WHERE customer_id = 203 
  OR amount = 3.96 ;

这里写图片描述

应尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
低效:select * from t_credit_detail where Flistid = '2000000608201108010831508721' or Flistid = '10000200001';

可以用下面这样的查询代替上面的 or 查询:
高效:select from t_credit_detail where Flistid = '2000000608201108010831508721' union all select from t_credit_detail where Flistid = '10000200001';

6 使用!= 或 <> 操作符时

尽量避免使用!= 或 <>操作符,否则数据库引擎会放弃使用索引而进行全表扫描。使用>或<会比较高效。

select * from t_credit_detail where Flistid != '2000000608201108010831508721'\G

7 对字段进行null值判断

应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
低效:select * from t_credit_detail where Flistid is null ;

可以在Flistid上设置默认值0,确保表中Flistid列没有null值,然后这样查询:
高效:select * from t_credit_detail where Flistid =0;

避免select *

在解析的过程中,会将'*' 依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间。

所以,应该养成一个需要什么就取什么的好习惯。

优化子查询

使用连接查询(join)代替子查询可以提高查询效率。

MySQL从4.1版开始支持子查询(一个查询的结果作为另一个select子句的条件),子查询虽然灵活但执行效率不高,因为使用子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录,查询完毕后 再撤销这些临时表,因此子查询的速度会相应的受到影响。而连接查询不需要建立临时表其查询速度快于子查询!

优化插入记录的速度

innoDB引擎的表常见的优化方法

(1)、禁用唯一性检查

插入数据时,MySQL会对插入的记录进行唯一性校验。这种唯一性校验会降低插入记录的速度。为了降低这种情况对查询速度的影响可以在插入记录之前禁用唯一性检查,等到记录插入完毕后再开启。

Set  unique_check=0; 开启唯一性检查的语句如下:set  unique_checks=1;

(2)、禁用外键检查

插入数据之前禁止对外键的检查,数据插入完成之后再恢复对外键的检查。

Set foreign_key_checks=0; 恢复外键检查:set foreign_key_checks=1;

(3)、禁止自动提交

插入数据之前禁止事务的自动提交,数据导入之后,执行恢复自动提交操作。

禁止自动提交的语句 set autocommit=0;恢复自动提交:set autocommit=1;

Myisam引擎表常见的优化方法

(1)、禁用索引 alter table table_name disable keys

            导入数据  loading the data

    开启索引 alter table table_name enable keys

(2)禁用唯一性检查

(3)使用批量插入

(4)当需要批量导入数据时,使用load data infile

优化insert语句

1. 一条SQL语句插入多条数据。
常用的插入语句如:

修改成:

修改后的插入操作能够提高程序的插入效率。这里第二种SQL执行效率高的主要原因是合并后日志量(MySQL的binlog和innodb的事务让日志)减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减少网络传输的IO。
这里提供一些测试对比数据,分别是进行单条数据的导入与转化成一条SQL语句进行导入,分别测试1百、1千、1万条数据记录。

2. 在事务中进行插入处理。

把插入修改成:

使用事务可以提高数据的插入效率,这是因为进行一个INSERT操作时,MySQL内部会建立一个事务,在事务内才进行真正插入处理操作。通过使用事务可以减少创建事务的消耗,所有插入都在执行后才进行提交操作。
这里也提供了测试对比,分别是不使用事务与使用事务在记录数为1百、1千、1万的情况。

3. 数据有序插入。
数据有序的插入是指插入记录在主键上是有序排列,例如datetime是记录的主键:

修改成:

由于数据库插入时,需要维护索引数据,无序的记录会增大维护索引的成本。我们可以参照innodb使用的B+tree索引,如果每次插入记录都在索引的最后面,索引的定位效率很高,并且对索引调整较小;如果插入的记录在索引中间,需要B+tree进行分裂合并等处理,会消耗比较多计算资源,并且插入记录的索引定位效率会下降,数据量较大时会有频繁的磁盘操作。

优化order by语句


ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序

MySQL支持二种方式的排序,FileSort和Index,后者效率高,它指MySQL扫描索引本身完成排序。FileSort方式效率较低。

ORDER BY满足以下情况,会使用Index方式排序:

a)ORDER BY 语句使用索引最左前列。参见第1句
b)使用Where子句与Order BY子句条件列组合满足索引最左前列。参见第2句.


以下情况,会使用FileSort方式的查询

a)检查的行数过多,且没有使用覆盖索引。

第3句,虽然跟第2句一样,order by使用了索引最左前列uid,但依然使用了filesort方式排序,因为status并不在索引中,所以没办法只扫描索引。

b)使用了不同的索引,MySQL每回只采用一个索引.

第4句,order by出现二个索引,分别是uid_fuid和聚集索引(pk)

c)对索引列同时使用了ASC和DESC。 通过where语句将order by中索引列转为常量,则除外。

第5句,和第6句在order by子句中,都出现了ASC和DESC排序,但是第5句却使用了filesort方式排序,是因为第6句where uid取出排序需要的数据,MySQL将其转为常量,它的ref列为const。

d)where语句与order by语句,使用了不同的索引。参见第7句。
e)where语句或者ORDER BY语句中索引列使用了表达式,包括函数表达式。参见第8,9句

f)where 语句与ORDER BY语句组合满足最左前缀,但where语句中使用了条件查询。

查见第10句,虽然where与order by构成了索引最左有缀的条件,但是where子句中使用的是条件查询。

g)order by子句中加入了非索引列,且非索引列不在where子句中。

h)order by或者它与where组合没有满足索引最左前列。

参见第11句和12句,where与order by组合,不满足索引最左前列. (uid, fsex)跳过了fuid

i)当使用left join,使用右边的表字段排序。

参见第13句,尽管user.uid是pk,依然会使用filesort排序。


FileSort排序算法

算法一:双路排序算法

只利用ORDERBY子句中包括的列对象进行排序(适用于有BLOB、TEXT类型的列对象参与的排序)

MySQL4.1之前的排序算法,完整实现过程如下:

1) 按索引键或全表扫描的方式,读取所有的元组,不匹配WHERE子句的元组被跳过;第一步需要从存储读入数据,引发I/O操作。

2) 对于每一行,在缓冲区中存储一对值(对值,包括排序关键字和元组指针)。缓冲区的大小是系统变量的sort_buffer_size设定的值。

3) 当缓冲区已满,运行快排算法(快速排序,qsort)对一个块中的数据进行排序,将结果存储在一个临时文件。保存一个指向排序后的块的指针(如果第二步所说的对值都能被缓冲区容纳,则不会创建临时文件)。

4) 重复上述步骤,直到所有的行已经被读取。

5) 执行一个多路归并操作(操作对象是第三步生成的每一个有序的块)汇集到“MERGEBUFF域”,然后存放到在第二个临时文件中。重复操作,直到第一个文件的所有块归并后存入到第二个文件;“MERGEBUFF域”是代码sql_sort.h中定义的宏,值为7。

6) 重复以下操作(第7步和第8步),直到留下少于“MERGEBUFF2域”标明的块数为止;“MERGEBUFF2域”是代码sql_sort.h中定义的宏,值为15。

7) 在最后一次多路归并操作中,把元组的指针(排序关键字的最后部分)写入到一个结果文件。

8) 在结果文件中,按照排列的顺序使用元组指针读取元组(为了优化这项操作,MySQL读入元组指针进入一个大的块,对块中元组指针进行排序而不是直接对数据排序,然后再用有序的元组指针获取元组到元组缓存,元组缓冲区的大小由read_rnd_buffer_size参数控制)。第8步需要从存储读入数据,引发I/O操作。

算法二:单路排序算法

除利用ORDERBY子句中包括的列对象外,还利用查询目标列中的所有列对象进行排序(适用于除BLOB、TEXT类型外的所有的其他类型的排序)

MySQL4.1之后出现的改进算法,减少一次I/O,需要增加缓冲区大小容纳更多信息。其具体实现过程如下:

1) 获取与WHERE子句匹配的元组。这一步需要从存储读入数据,引发I/O操作。

2) 对于每一个元组,记录排序键值、行的位置值、查询所需的列。这一步记录更多内容,需要更大缓存,内存存储一条元组的信息的长度比算法一的“对值”大许多,这可能引发排序速度问题(排序对象的长度变长,但是内存有限,所以就需把一次内存排序变为多次,进而影响排序的速度),为了控制这个问题,MySQL引入一个参数“max_length_for_sort_data”,如果这一步得到的元组长度大于这个值,则不使用算法二。需要MySQL的使用者特别注意的是,在排序中,如果存在“很高磁盘I/O和很低的CPU利用率”的现象,则需要考虑调整“max_length_for_sort_data”的大小以变更换排序算法。

3) 按照排序的键值,对元组(元组是第二步的结果)进行排序。

算法二直接从缓冲区中的排序的元组中获取有序的列信息等(查询的目的对象),而不是第二次访问该表读取所需的列。相比算法一减少一次I/O。

FileSort优化策略

当无法使用索引列排序时,为了提高Order By的速度,应该尝试一下优化: 
1、避免使用 “select * ” 。查询的字段越多导致元组长度总合可能

超过max_length_for_sort_data的设置,导致无法使用单路排序算法,只能用双路排序算法。 
超过sort_buffer_size的设置,超出后会创建tmp文件进行合并,导致多次IO

2、适当增大sort_buffer_size参数的设置

3、适当增大max_length_for_sort_data参数的设置


优化group by语句

默认情况下,MySQL对所有group by col1,col2,...的字段进行排序,若查询包括group by 但用户想避免排序结果的消耗,可以指定order by null禁止排序。

提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉

低效:

SELECT JOB , AVG(SAL)

FROM EMP

GROUP by JOB

HAVING JOB = ‘PRESIDENT'

OR JOB = ‘MANAGER'

高效:

SELECT JOB , AVG(SAL)

FROM EMP

WHERE JOB = ‘PRESIDENT'

OR JOB = ‘MANAGER'

GROUP by JOB

优化嵌套查询

用关联查询代替子查询。使用join优化子查询(in)

优化or条件

(1) where 语句里面如果带有or条件, myisam表能用到索引, innodb不行。

1)myisam表:
 CREATE TABLE IF NOT EXISTS `a` (
  `id` int(1) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,
  `aNum` char(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `uid` (`uid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

mysql> explain select * from a where id=1 or uid =2;
+----+-------------+-------+-------------+---------------+-------------+---------+------+------+---------------------------------------+
| id | select_type | table | type        | possible_keys | key         | key_len | ref  | rows | Extra                                 |
+----+-------------+-------+-------------+---------------+-------------+---------+------+------+---------------------------------------+
|  1 | SIMPLE      | a     | index_merge | PRIMARY,uid   | PRIMARY,uid | 4,4     | NULL |    2 | Using union(PRIMARY,uid); Using where |
+----+-------------+-------+-------------+---------------+-------------+---------+------+------+---------------------------------------+
1 row in set (0.00 sec)

2)innodb表:

CREATE TABLE IF NOT EXISTS `a` (
  `id` int(1) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,
  `aNum` char(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `uid` (`uid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

mysql>  explain select * from a where id=1 or uid =2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | a     | ALL  | PRIMARY,uid   | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


(2) 含有or的查询子句,如果要利用索引,则or之间的每个条件列都必须用到索引,若没有索引,则应考虑增加索引。

(3) 用union替换or:

   通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 

       注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低. 

       在下面的例子中, LOC_ID 和REGION上都建有索引.
       高效: 

  1. select loc_id , loc_desc , region from location where loc_id = 10
  2. union
  3. select loc_id , loc_desc , region from location where region = "melbourne"
     低效: 
select loc_id , loc desc , region from location where loc_id = 10 or region = "melbourne"

如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.

(4) 用in替换or:

实际执行效果还需检验:

低效: 
select…. from location where loc_id = 10 or loc_id = 20 or loc_id = 30 
高效 
select… from location where loc_in in (10,20,30);

优化分页查询

一般分页查询

一般的分页查询使用简单的 limit 子句就可以实现。limit 子句声明如下:

SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset

LIMIT 子句可以被用于指定 SELECT 语句返回的记录数。需注意以下几点:

第一个参数指定第一个返回记录行的偏移量
第二个参数指定返回记录行的最大数目

如果只给定一个参数:它表示返回最大的记录行数目
第二个参数为 -1 表示检索从某一个偏移量到记录集的结束所有的记录行
初始记录行的偏移量是 0(而不是 1)

下面是一个应用实例:

select * from orders_history where type=8 limit 1000,10;

该条语句将会从表 orders_history 中查询第1000条数据之后的10条数据,也就是第1001条到第10010条数据。

数据表中的记录默认使用主键(一般为id)排序,上面的结果相当于:

select * from orders_history where type=8 order by id limit 10000,10;

这种分页查询方式会从数据库第一条记录开始扫描,越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度。

(1) 使用子查询优化

这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。

select * from orders_history where type=8 limit 100000,1;
 
select id from orders_history where type=8 limit 100000,1;
 
select * from orders_history where type=8 and
id>=(select id from orders_history where type=8 limit 100000,1) 
limit 100;
 
select * from orders_history where type=8 limit 100000,100;
?

4条语句的查询时间如下:

?
1
2
3
4
第1条语句:3674ms
第2条语句:1315ms
第3条语句:1327ms
第4条语句:3710ms

针对上面的查询需要注意:

比较第1条语句和第2条语句:使用 select id 代替 select * 速度增加了3倍
比较第2条语句和第3条语句:速度相差几十毫秒
比较第3条语句和第4条语句:得益于 select id 速度增加,第3条语句查询速度增加了3倍
这种方式相较于原始一般的查询方法,将会增快数倍。

(2) 使用 id 限定优化

这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询:

select * from orders_history where type=2 and id between 1000000 and 1000100 limit 100;
这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况,不过一般建立表的时候,都会添加基本的id字段,这为分页查询带来很多便利。

还可以有另外一种写法:

select * from orders_history where id >= 1000001 limit 100;

当然还可以使用 in 的方式来进行查询,这种方式经常用在多表关联的时候进行查询,使用其他表查询的id集合,来进行查询:

select * from orders_history where id in (select order_id from trade_2 where goods = 'pen') limit 100;

这种 in 查询的方式要注意:某些 mysql 版本不支持在 in 子句中使用 limit。

select film_id, description from film order by title limit 50,5;

优化后:

select film_id, description from film a inner join (select film_id from film order by title limit 50,5) b on a.film_id=b.film_id;

能用UNION ALL就不要用UNION

UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源。

在Join表的时候使用相当类型的列,并将其索引

如果应用程序有很多JOIN 查询,你应该确认两个表中Join的字段是被建过索引的。这样,MySQL内部会启动为你优化Join的SQL语句的机制。

而且,这些被用来Join的字段,应该是相同的类型的。例如:如果你要把 DECIMAL 字段和一个 INT 字段Join在一起,MySQL就无法使用它们的索引。对于那些STRING类型,还需要有相同的字符集才行。(两个表的字符集有可能不一样)

能用DISTINCT的就不用GROUP BY

SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID

可改为:

SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10

使用 varchar/nvarchar 代替 char/nchar

尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

MySQL多表联查如何建立索引? 在 MySQL 数据库中,设计索引主要是为了提高查询的效率,降低数据库的压力。当我们进行多表查询时,正确设计索引非常重要。 阅读详情

相关推荐

PySpark 本地开发环境搭建与实践

本文详细介绍了 PySpark 本地开发环境的搭建过程,包括 JDK、Hadoop、Anaconda、PySpark 的安装以及 Pycharm 工程的创建。同时,深入讲解了代码编写、本地开发案例(如 WordCount、处理特殊分隔符、读取 hdfs 数据、获取外部变量)、Spark 程序的监控和 local 模式下结果文件数量问题等内容。通过掌握这些知识和技能,读者可以在 Windows 本地环境中高效地进行 PySpark 开发,处理大规模数据,解决实际业务中的数据分析和处理问题。

天冬忘忧的博客 3013

left join 索引笔记

sql join 索引测试 基础

史上最强生物的博客 4079

【前端HTML生成条形码——MQ】

本文将展示前端HTML如何根据用户输入内容生成对应的条形码,附HTML和JS代码。代码如下(示例):

weixin_42588676的博客 1955

查一次left join没有走索引以及原因

线上有个查询sql,原来是inner join 查询没有问题,后来应业务要求改成left join之后, 查询时间就暴涨了 需要长达24s 通过explain分析,发现订单表没有走索引 ,分析之后解决了,记录下来。 为了简洁起见,这里就将无关的查询字段都用* 具体sql如下 SELECT * from t_item_detail a left join t_order_detail d ...

hello world 4万+

ORB-SLAM3的Euroc数据集测试

(一)测试运行 不同模式测试过程(以MH_03为例) 1、pure mono 运行SLAM: cd ORB-SLAM3/Example #run slam ./Monocular/mono_euroc ../Vocabulary/ORBvoc.txt ./Monocular/EuRoC.yaml "$pathDatasetEuroc"/MH03 ./Monocular/EuRoC_TimeStamps/MH03.txt dataset-MH03_mono 利用ORB-SLAM3自带..

ljtx200888的博客 9146

你需要这样一个Ros软路由—— 路由器+外网+一号通ip线路=动态ip的WiFi信号

功能强大 管理便捷—给您全新的路由体验 一键更换指定线路or批量更换所有IP/MAC/SSID 自定义走本地网络策略的分流功能 设备批发价、不限制拨号账号服务商 强大的单设备/多设备IP去重功能 批量导入、管理一号通线路 一键任意切换5G_WiFi(推荐)/2.4G_WiFi(建议不用) 设备支持PPTP/L2TP/SSTP/openVP.N等协议 独家支持openVPN,适用于网络受限用户 支持自行接入AP和交换机扩容 一键打开/关闭所有虚拟WiFi 一键隐藏/显示设备WiFi...

米粒儿 4253

MSQL系列(十三) Mysql实战-left/right/inner join 使用详解及索引优化

前面我们讲解了B+Tree的索引结构,也详细讲解下Join的底层驱动表 选择原理,今天我们来了解一下为什么会出现内连接外连接,两种连接方式,另外实战一下内连接和几种最常用的join语法。这个就会带来一个问题, 比如我的驱动表有100条记录,但是我的外连接 我不想让驱动表全部数据加入到结果集, 但是外连接的本质就是不匹配的就展示到结果集,这种情况该如何处理?要按照错误的这个说法,下面的语句执行完 左边不动,还是4条,1,2,3,4 但是明显不是。根据查询结果,我们可以很明确的知道。

流浪的喵的博客 4801

零信任架构实战:“持续验证+动态授权”全流程解析(附策略引擎联动图)

《零信任实战指南:7图拆解核心流程与行业案例》摘要:本文通过7张架构图系统解析零信任五大核心流程:强身份认证、设备检查、动态授权、持续监控和自动降权。对比金融(重数据审计)与制造业(重物理绑定)的落地差异,指出三大常见误区及解决方案。数据显示,零信任可使安全响应提速60%,泄露成本降低45%。文章提供6个月实施路线图,强调零信任是"智能信任"体系,建议企业分阶段改造,优先保护核心系统。附赠金融/制造行业策略模板及甘特图示例。(149字)

sara_han的博客 776

(索引)使用索引进行查询优化;常用mysql优化

https://blog.youkuaiyun.com/qq_22238021/article/details/80922166 索引有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索...

baidu_32542573的博客 597

3dsMax高效导入OSGB倾斜模型的3个关键步骤与插件应用

本文详细解析了在3dsMax中高效导入OSGB倾斜模型的三个核心步骤:建立索引、处理贴图路径以及选择合适的插件。针对导入过程中常见的模型崩溃、贴图丢失和操作卡顿问题,提供了从数据结构理解到插件选型的实战解决方案,帮助用户实现大规模实景模型在3dsMax中的流畅导入与编辑。

weixin_29238147的博客 469

C#与倍福TwinCAT3通信实战:ADS协议封装与设备变量读写完整源码

倍福(Beckhoff)TwinCAT3 作为工业自动化领域主流的软PLC系统,其内置的ADS(Automation Device Specification)协议是实现上位机与TwinCAT3通信的核心标准。传统ADS通信开发存在门槛高(协议细节复杂)、稳定性差(缺乏统一异常处理)、复用性低(重复编码)等问题。本文基于 C# 技术栈,聚焦“协议封装标准化、变量读写易用化、通信稳定工业化”核心需求,提供一套完整的 ADS 协议封装方案与设备变量读写源码。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1987

关于查询时间范围的 如何做索引优化_项目中常用的19条MySQL优化技巧

声明一下:下面的优化方案都是基于 “ Mysql-索引-BTree类型 ”。一 善用EXPLAIN做MySQL优化,我们要善用 EXPLAIN 查看SQL执行计划。下面来个简单的示例,标注(1,2,3,4,5)我们要重点关注的数据1、type列: 连接类型。一个好的sql语句至少要达到range级别。杜绝出现all级别2、key列: 使用到的索引名。如果没有选择索引,值是NULL。可以采取强制索引...

weixin_39983384的博客 3861

采样率转化代码C++(有理倍数,升采样、降采样均可)

【代码】采样率转化(有理倍数,升采样、降采样均可)

goudahai的专栏 547

mysql 不等于查询优化_MySQL 索引及查询优化总结

本文由云+社区发表文章《MySQL查询分析》讲述了使用MySQL慢查询和explain命令来定位mysql性能瓶颈的方法,定位出性能瓶颈的sql语句后,则需要对低效的sql语句进行优化。本文主要讨论MySQL索引原理及常用的sql查询优化。一个简单的对比测试前面的案例中,c2c_zwdb.t_file_count表只有一个自增id,FFileName字段未加索引的sql执行情况如下:在上图中,ty...

weixin_39887961的博客 1256

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

mysql 多个索引下的查询 php_MySQL索引以及查询优化的详细介绍

本篇文章给大家带来的内容是关于MySQL索引以及查询优化的详细介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。文章《MySQL查询分析》讲述了使用MySQL慢查询和explain命令来定位mysql性能瓶颈的方法,定位出性能瓶颈的sql语句后,则需要对低效的sql语句进行优化。本文主要讨论MySQL索引原理及常用的sql查询优化。一个简单的对比测试前面的案例中,c2c_zwdb...

weixin_35846141的博客 313

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

MySQL索引为什么可以优化查询效率

本文可能只是简单地解释了索引优化查询效率地原因,文字也是向ai问的,当然我觉得其中大致过程是这样的,细节的地方可能不好把控,毕竟我是开始学索引不久,有问题的地方请多多指教

2301_79621117的博客 2231

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

MySQL数据库的索引优化与查询计划分析:提升查询性能的秘密武器!

在Web应用的开发中,数据库的查询性能往往是性能瓶颈的关键所在。对于MySQL等关系型数据库来说,索引就像是一位精准的导游,帮助我们快速定位数据。如果没有索引,数据库在处理查询时会进行全表扫描,导致查询效率低下,严重影响应用的响应速度。然而,索引的设计并不是越多越好,合理的索引设计与查询优化才是提升数据库性能的关键。本文将深入探讨如何通过索引优化和查询计划分析来提升MySQL的查询性能。我们将从MySQL索引的基本概念、索引优化技巧、查询计划分析工具(如EXPLAIN。

2201_75863687的博客 1036

MySQL秘籍之索引与查询优化实战指南

最左前缀原则。不冗余原则。最大选择性原则。所谓前缀索引,说白了就是对文本的前几个字符建立索引(具体是几个字符在建立索引时去指定),比如以产品名称的前 10 位来建索引,这样建立起来的索引更小,查询效率更快!

千寻简笔记《chihiro-notes》已开源|公众号:千寻简 964

mysql查询怎么强制使用索引_mysql force Index 查询强制使用索引

其他强制操作,优先操作如下:mysql常用的hint对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法。同样,在mysql里,也有类似的hint功能。下面介绍一些常用的。强制索引 FORCE INDEXSELECT * FROM TABLE1 FORCE INDEX (FIELD1) …以上的SQL语句只使用建立在FIELD1上的索引,而不...

weixin_39769406的博客 814

MySQL优化查询性能的常用方法有哪些?

优化MySQL查询性能是一个多方面的过程,涉及数据库设计、索引策略、查询编写以及服务器配置等多个方面。

qq_33240556的博客 667

MySQL优化-MySQL常用查询命令

MySQL优化-MySQL常用查询命令

weixin_45226668的博客 903

MYSQL索引优化实战一:1,如何提高索引命中率;2,in/or查询优化;3,order by/group by查询优化;4;filesort原理

MYSQL 优化实战,开发常用sql优化原理及技巧

aquriushu的博客 1412

MySQL索引及查询优化总结

本文转载:https://www.qcloud.com/community/article/382852?fromSource=gwzcw.107784.107784.107784 感谢作者君 一个简单的对比测试 前面的案例中,c2c_zwdb.t_file_count表只有一个自增id,FFileName字段未加索引的sql执行情况如下: 在上图中,type=all,key=...

fjz_lihuapiaoxiang的博客 167

mysql 强制索引_MYSQL中常用的强制性操作(例如强制索引)

其他强制操作,优先操作如下:mysql常用的hint对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法。同样,在mysql里,也有类似的hint功能。下面介绍一些常用的。强制索引 FORCE INDEXSELECT * FROM TABLE1 FORCE INDEX (FIELD1) …以上的SQL语句只使用建立在FIELD1上的索引,而不...

weixin_34763548的博客 519

MySQL索引——如何提高查询速度

create INDEX 索引名 ON TABLE 表名(字段)复制代码创建表的同时创建索引的语法:create table 表名字段 数据类型,{INDEX | KEY} 索引名(字段)复制代码修改表的同时创建索引的语法:alter table 表名 ADD {INDEX | KEY} 索引名(字段)复制代码注意:给表设定主键约束或者唯一性约束的时候,MySQL 会自动创建主键索引或唯一性索引。

2401_86400401的博客 1229
上一篇: MySql索引类型
下一篇: MySQL正则表达式
Unique-You
博客等级 码龄12年 591粉丝 199原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值