mysql 执行计划 代价_order by、limit对mysql执行计划的影响实例

问题引入

order by、limit语句会影响mysql索引执行计划,mysql可能会使用我们认为不合理的索引,(但对mysql自身来说认为是合理的)。

具体实例

表结构简化后:

CREATE TABLE `test` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增长主键',

`shop_id` int(11) NOT NULL COMMENT '商户id',

`booking_time` datetime NOT NULL COMMENT '用餐时间',

`created_time` datetime NOT NULL COMMENT '创建时间',

`updated_time` datetime NOT NULL COMMENT '更新时间',

`other_column` int(11) NOT NULL DEFAULT '0' COMMENT '其他还有约20个未列举出来的字段',

PRIMARY KEY (`id`),

KEY `IX_shop_id_booking_time` (`shop_id`,`booking_time`),

KEY `IX_updated_time` (`updated_time`),

KEY `IX_created_time` (`created_time`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='示例表'

SQL语句简化后:

1、select count(*) from test where shop_id = 12594791; 有3w条数据

2、explain select * from test where shop_id = 12594791 order by created_time;

执行计划为: type ref

possible_keys IX_created_time,IX_shop_id_booking_time

key IX_shop_id_booking_time

rows 56920

Extra Using index condition; Using filesort

即通过索引IX_shop_id_booking_time查找数据后,mysql对数据集排序,这里的Using filesort并不一定是磁盘排序,也可能是在内存中完成,与缓冲区大小相关,更多可google之,这里提供一篇可参考文章:http://www.linuxidc.com/Linux/2016-08/133838.htm

3、explain select * from test where shop_id = 12594791 order by created_time limit 0, 20;

执行计划主要内容为:

type index

possible_keys IX_created_time,IX_shop_id_booking_time

key IX_created_time

rows 10697

Extra Using where

即通过扫描索引树IX_created_time,然后回表查询数据,用where条件过滤,直到扫描得到的结果集大小有20条数据就终止。

可以看到,加上limit 0, 20后执行计划有所变化,因为mysql查询优化器主要是基于成本考虑的,这里成本主要指读取数据的IO成本。mysql认为针对这次查询只需顺序扫描created_time索引,然后回表查询过滤就能得到结果,而不需要额外的排序代价了,当然,这里与特定条件的数据相关,shop_id = 12594791的数据有3w条,排序的代价很高。如果是数据较小的shop_id,仍然会采用IX_shop_id_booking_time索引。

经过上面的解析,我们可以猜测,如果limit的偏移量较大的话,通过顺序扫描created_time的数据会很多而导致扫描行数激增,那么仍然会用IX_shop_id_booking_time索引。 接下来的验证情况:

4、explain select * from YY_BookingRecord where shop_id = 12594791 order by created_time limit 1000, 20;

执行计划主要内容为: type ref

possible_keys IX_created_time,IX_shop_id_booking_time

key IX_shop_id_booking_time

rows 56956

Extra Using index condition; Using filesort

与sql语句2的执行计划相同

实际问题

线上服务业务执行了sql语句3,虽然mysql认为是较优的执行计划,实际导致了慢查询的出现。

解决方案

针对where条件与order by的条件增加联合索引,对应上述实例即增加shop_id,created_time的联合索引

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MySQL 视图的限制包括: 1. 视图不能使用临时表 2. 视图不能包含 ORDER BY 子句,除非同时使用了 TOP 或 LIMIT 子句 3. 视图不能包含 INTO OUTFILE 或 INTO DUMPFILE 子句 4. 视图不能被索引,也不能被视为基表 5. 视图不能修改基表的数据,除非使用了特定的 WITH CHECK OPTION 子句 下面是一个 MySQL 视图限制的实例: 假设有一个名为 `orders` 的表,包含以下字段:`order_id`、`customer_id`、`order_date` 和 `total_amount`。 我们可以创建一个名为 `orders_view` 的视图,它只包含 `customer_id` 和 `total_amount` 这两个字段,如下所示: ``` CREATE VIEW orders_view AS SELECT customer_id, total_amount FROM orders; ``` 然而,我们不能在这个视图中包含 ORDER BY 子句,否则会收到以下错误消息: ``` ERROR 1351 (HY000): View's SELECT contains a subquery in the FROM clause ``` 因此,我们应该在使用 ORDER BY 子句时,同时使用 TOP 或 LIMIT 子句来限制结果集的大小,如下所示: ``` CREATE VIEW orders_view AS SELECT customer_id, total_amount FROM orders ORDER BY total_amount DESC LIMIT 10; ``` 这样就可以避免上述错误。 ### 回答2: MySQL视图是虚拟的表,它是根据定义视图时指定的查询语句动态生成的,可以简化复杂的查询操作。然而,MySQL视图也有一些限制。 首先,MySQL视图不支持带有全局或本地临时表的查询。这意味着如果查询需要使用临时表,无法将其放在视图中进行处理。 其次,MySQL视图不能索引。因为视图是根据查询结果动态生成的,而不是实际存储数据,所以无法为视图创建索引。这可能会导致在对视图进行复杂查询时性能下降。 此外,MySQL视图还有许多使用限制。例如,视图不能引用临时表、不能使用存储函数、不能使用用户变量,并且定义视图的SELECT语句不能包含DISTINCT关键字。 下面是一个关于MySQL视图限制的示例: 假设有一个名为"employees"的表,包含员工的姓名、年龄和工资信息。我们希望创建一个名为"young_employees"的视图,只包含年龄小于30岁的员工信息。 创建视图的语句可以是: CREATE VIEW young_employees AS SELECT * FROM employees WHERE age < 30; 然而,如果我们尝试在这个视图上使用DISTINCT关键字进行查询,就会遇到限制: SELECT DISTINCT * FROM young_employees; 会报错,因为MySQL不允许在视图的查询中使用DISTINCT关键字。 综上所述,MySQL视图不支持临时表、无法索引、存在许多其他使用限制。在使用MySQL视图时,我们应该遵守这些限制并考虑它们可能带来的性能问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值