范围查询 range级别 继续优化思路

问题:

这几天工作遇到了一个问题。千万级别的表,每秒钟产生很多数据,select count(id) from table where flag = 1 and create_time < 2023.11.07;分区表,range级别,已经是走create_time列上的索引,flag的值只有0,1。厂商业务卡死在这条sql语句。有什么办法还能再通过什么手段优化吗。大家不妨想一想。

初看已经走索引,range级别好像已经够优秀了,但是执行计划产生了回表,看查找的列不是select *。很好我们可以通过创建联合索引避免回表。

create index inx_caf on table(create_time,flag);

实验1(name的索引选择性还不错),验证具体有没有优化:

-- 创建结构相似的表
create table lian(
	id int primary key,
	name varchar(10),
	flag varchar(10),
	unique key inx_name(name),
	key inx_flag(flag)
)
-- 创建存储过程,插入flag分别为0,1的数据
delimiter $$  # 定义结束符
drop procedure if exists addTestData; # 存储过程名叫:addTestData
create procedure addTestData()
begin
declare number int;
set number = 20001;
while number <= 30000 #插入N条数据
do
insert into lian
values(null,number+'1',0);  # 为了区分姓名,我们加上后缀
set number = number + 1;
end
while;
end $$;
select count(*) from lian;
select count(*) from lian where flag = 0;
select count(*) from lian where flag = 1;

已知:现在表中name列和flag列分别有单列索引,我们按找卡死的sql语句运行。

explain
select count(id) from lian   where flag = 1 and name < '1000';

explain format=json
select count(id) from lian   where flag = 1 and name < '1000';
{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "5.21"
    },
    "table": {
      "table_name": "lian",
      "access_type": "range",
      "possible_keys": [
        "inx_name",
        "inx_flag"
      ],
      "key": "inx_name",
      "used_key_parts": [
        "name"
      ],
      "key_length": "13",
      "rows_examined_per_scan": 3,
      "rows_produced_per_join": 0,
      "filtered": "10.00",
      "index_condition": "(`test2`.`lian`.`name` < '1000')",
      "cost_info": {
        "read_cost": "5.15",
        "eval_cost": "0.06",
        "prefix_cost": "5.21",
        "data_read_per_join": "9"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "(`test2`.`lian`.`flag` = 1)"
    }
  }
}

可以看到这就如厂商卡到的sql语句一样,并且范围查询如果 范围过大的话,执行计划就会变成全表扫描。执行代价5.21

创建联合索引:

create index inx_naf on lian(name,flag);

可以看到联合索引消除了回表操作。让我们看看执行代价:

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "2.22"
    },
    "table": {
      "table_name": "lian",
      "access_type": "range",
      "possible_keys": [
        "inx_name",
        "inx_flag",
        "inx_naf"
      ],
      "key": "inx_naf",
      "used_key_parts": [
        "name"
      ],
      "key_length": "13",
      "rows_examined_per_scan": 3,
      "rows_produced_per_join": 0,
      "filtered": "10.00",
      "using_index": true,
      "cost_info": {
        "read_cost": "2.16",
        "eval_cost": "0.06",
        "prefix_cost": "2.22",
        "data_read_per_join": "9"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "((`test2`.`lian`.`flag` = 1) and (`test2`.`lian`.`name` < '1000'))"
    }
  }
}

2.22比之走单列索引的5.21小了很多(我后续做了实验,小这么多的原因是因为name列是唯一约束,或者说name列的唯一值特别多。后续也做了唯一值特别少的代价实验,请往后看)

联合索引的考量

众所周知联合索引设在前谁在后是有考量的,规则就是谁的选择性好(相对来说唯一值多)谁就放在前面 ,所以我先入为主就把create_time放在了前面。让我们测试下flag在前面的情况。

-- 还没删除naf
create index inx_fan on lian(flag,name);
explain 
select count(id) from lian   where flag = 1 and name < '1000';
explain format=json
select count(id) from lian   where flag = 1 and name < '1000';

 可以看到在两个索引上还是选择了naf。

删除naf:

 优化器没有选择fan,而是选择了最初的单列索引,产生回表。

让我们强制走fan,看看执行代价:

explain format=json
select count(id) from lian force index(inx_fan) where flag = 1 and name < '1000';

explain
select count(id) from lian force index(inx_fan) where flag = 1 and name < '1000';

 变成了索引树扫描而非range。

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "35755.00"
    },
    "table": {
      "table_name": "lian",
      "access_type": "index",
      "possible_keys": [
        "inx_fan"
      ],
      "key": "inx_fan",
      "used_key_parts": [
        "flag",
        "name"
      ],
      "key_length": "26",
      "rows_examined_per_scan": 29795,
      "rows_produced_per_join": 993,
      "filtered": "3.33",
      "using_index": true,
      "cost_info": {
        "read_cost": "35556.39",
        "eval_cost": "198.61",
        "prefix_cost": "35755.00",
        "data_read_per_join": "31K"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "((`test2`.`lian`.`flag` = 1) and (`test2`.`lian`.`name` < '1000'))"
    }
  }
}

 执行代价35755特别大,所以联合索引不可以把flag放在最前面,索引选择性特别低。

实验2(name列的索引选择度也特别低)

create table lian3(
	id int primary key,
	name varchar(10),
	flag varchar(10),
	key inx_flag(flag)
)

delimiter $$  # 定义结束符
drop procedure if exists addTestData; # 存储过程名叫:addTestData
create procedure addTestData()
begin
declare number int;
set number = 40001;
while number <= 45000 #插入N条数据
do
insert into lian3
values(null,'h',0);  # 为了区分姓名,我们加上后缀
set number = number + 1;
end
while;
end $$;

call addTestData();

分别看name和flag的索引选择度


select count(distinct(name))/count(*),count(distinct(name)),count(*) from lian3;
select count(distinct(flag))/count(*),count(distinct(flag)),count(*) from lian3;

 

 

explain
select count(id) from lian3  where flag = 1 and name < 'e';
explain format=json
select count(id) from lian3  where flag = 1 and name < 'e';

 全表扫描执行代价:

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "6035.00"
    },
    "table": {
      "table_name": "lian3",
      "access_type": "ALL",
      "possible_keys": [
        "inx_flag"
      ],
      "rows_examined_per_scan": 29690,
      "rows_produced_per_join": 989,
      "filtered": "3.33",
      "cost_info": {
        "read_cost": "5837.09",
        "eval_cost": "197.91",
        "prefix_cost": "6035.00",
        "data_read_per_join": "30K"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "((`test2`.`lian3`.`flag` = 1) and (`test2`.`lian3`.`name` < 'e'))"
    }
  }
}

创建name单列索引,执行计划:

create index inx_name on lian3(name);

 因为name的选择度特别低,所以必须强制走索引

explain
select count(id) from lian3 force index(inx_name)  where flag = 1 and name < 'e';

explain format=json
select count(id) from lian3 force index(inx_name)  where flag = 1 and name < 'e';

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "20784.01"
    },
    "table": {
      "table_name": "lian3",
      "access_type": "range",
      "possible_keys": [
        "inx_name"
      ],
      "key": "inx_name",
      "used_key_parts": [
        "name"
      ],
      "key_length": "13",
      "rows_examined_per_scan": 14845,
      "rows_produced_per_join": 1484,
      "filtered": "10.00",
      "index_condition": "(`test2`.`lian3`.`name` < 'e')",
      "cost_info": {
        "read_cost": "20487.11",
        "eval_cost": "296.90",
        "prefix_cost": "20784.01",
        "data_read_per_join": "46K"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "(`test2`.`lian3`.`flag` = 1)"
    }
  }
}

创建联合索引naf,执行代价:

create index inx_naf on lian3(name,flag);

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "5993.18"
    },
    "table": {
      "table_name": "lian3",
      "access_type": "range",
      "possible_keys": [
        "inx_flag",
        "inx_name",
        "inx_naf"
      ],
      "key": "inx_naf",
      "used_key_parts": [
        "name"
      ],
      "key_length": "13",
      "rows_examined_per_scan": 14845,
      "rows_produced_per_join": 1484,
      "filtered": "10.00",
      "using_index": true,
      "cost_info": {
        "read_cost": "5696.29",
        "eval_cost": "296.90",
        "prefix_cost": "5993.19",
        "data_read_per_join": "46K"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "((`test2`.`lian3`.`flag` = 1) and (`test2`.`lian3`.`name` < 'e'))"
    }
  }
}

创建联合索引fan,并且删除naf,执行代价:

create index inx_fan on lian3(flag,name);
drop index inx_naf on lian3;

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "6035.00"
    },
    "table": {
      "table_name": "lian3",
      "access_type": "index",
      "possible_keys": [
        "inx_flag",
        "inx_name",
        "inx_fan"
      ],
      "key": "inx_fan",
      "used_key_parts": [
        "flag",
        "name"
      ],
      "key_length": "26",
      "rows_examined_per_scan": 29690,
      "rows_produced_per_join": 1484,
      "filtered": "5.00",
      "using_index": true,
      "cost_info": {
        "read_cost": "5738.10",
        "eval_cost": "296.90",
        "prefix_cost": "6035.00",
        "data_read_per_join": "46K"
      },
      "used_columns": [
        "id",
        "name",
        "flag"
      ],
      "attached_condition": "((`test2`.`lian3`.`flag` = 1) and (`test2`.`lian3`.`name` < 'e'))"
    }
  }
}

实验2总结:

全表扫描:6035

单列name索引:20784

naf:5993.18

fan:6035

可以看到naf和fan相差不大,这和name列的选择度低有关,但是就算选择度低,naf也是最优解,所以选择naf是最好的。

实验3(flag列选择性好):

这就根本不用做实验了,flag等值查询,选择性还好肯定放在联合索引的左侧。

综上所述,不管是什么做实验时硬道理,实践出真理。也要直到range级别了也可以继续优化,优化的一个思路就是创建联合索引避免回表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/178385.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

印刷企业实施WMS仓储管理系统需要哪些硬件设施

随着科技的快速发展&#xff0c;印刷企业的运营模式也正在经历着变革。为了提升效率&#xff0c;降低成本&#xff0c;并实现精细化管理&#xff0c;越来越多的印刷企业开始引入WMS仓储管理系统解决方案。然而&#xff0c;要成功实施这样的系统&#xff0c;必要的硬件设施是不可…

【Redis】持久化-RDBAOF混合持久化

文章目录 前置知识RDB&#xff08;定期备份&#xff09;触发机制流程说明RDB文件的处理RDB 的优缺点 AOF&#xff08;实时备份&#xff09;使用AOF命令写入AOF工作流程文件同步重写机制重写触发机制AOF进制重写流程 混合持久化启动时数据恢复 总结 前置知识 回顾MySQL MySQL的事…

upload-labs关卡12(基于白名单的%00截断绕过)通关思路

文章目录 前言一、靶场需要了解的前置知识1、%00截断2、0x00截断3、00截断的使用条件1、php版本小于5.3.292、magic_quotes_gpc Off 二、靶场第十二关通关思路1、看源代码2、bp抓包%00截断3、验证文件是否上传成功 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识&…

山西电力市场日前价格预测【2023-11-23】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-23&#xff09;山西电力市场全天平均日前电价为148.77元/MWh。其中&#xff0c;最高日前电价为420.40元/MWh&#xff0c;预计出现在18:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

谷歌开发者账号登录提示“存在异常活动”的原因及解决方法

相信很多开发者在登录谷歌开发者账号时遇到过这样的情况&#xff1a;“Verify your identity” “Weve detected unusual activity on the accountyoure trying to access. To continue, please followthe instructions below.” “验证您的身份&#xff0c;我们已经检测到你…

Spring Cloud学习(十一)【深入Elasticsearch 分布式搜索引擎03】

文章目录 数据聚合聚合的种类DSL实现聚合RestAPI实现聚合 自动补全拼音分词器自定义分词器自动补全查询completion suggester查询RestAPI实现自动补全 数据同步数据同步思路分析实现elasticsearch与数据库数据同步 集群搭建ES集群创建es集群集群状态监控创建索引库1&#xff09…

优先经验回放(prioritized experience replay)

prioritized experience replay 思路 优先经验回放出自ICLR 2016的论文《prioritized experience replay》。 prioritized experience replay的作者们认为&#xff0c;按照一定的优先级来对经验回放池中的样本采样&#xff0c;相比于随机均匀的从经验回放池中采样的效率更高&…

matlab绘图函数plot和fplot的区别

一、背景 有的函数用plot画就会报错&#xff0c;显示数据必须为可转换为双精度值的数值、日期时间、持续时间、分类或数组。 如下图所示&#xff1a; 但用fplot函数就没有问题&#xff0c;因此这里记录一下两者的区别&#xff0c;如果使用不当&#xff0c;画出的图可能就是下…

坚鹏:中国工商银行数字化转型发展现状与成功案例培训圆满结束

中国工商银行围绕“数字生态、数字资产、数字技术、数字基建、数字基因”五维布局&#xff0c;深入推进数字化转型&#xff0c;加快形成体系化、生态化实施路径&#xff0c;促进科技与业务加速融合&#xff0c;以“数字工行”建设推动“GBC”&#xff08;政务、企业、个人&…

用 jmeter 对 mongodb 进行测试方法合集

MongoDB 作为非关系型数据库&#xff0c;在现在企业中&#xff0c;还是有广泛的使用。但是&#xff0c;用 jmeter 如何测试 MongoDB&#xff0c;却是一个令很多人头疼的问题。去搜索&#xff0c;国内基本找不到一篇比较有价值的文章。 今天&#xff0c;我就用三种不同方法&…

如何通过RA过程识别Redcap UE?

以下是38.300中的描述 RedCap UE可以通过发送MSG3/MSGA的特定LCID识别&#xff0c;可选条件是通过MSGA/MSG1的PRACH occasion/PRACH preamble识别&#xff0c;根据这段描述&#xff0c;通过MSG3/MSGA的识别是必须项&#xff0c;而MSGA/MSG1的识别过程是可选项。如果通过MSGA/MS…

02 请求默认值

一、HTTP请求默认值&#xff1a;是用来管理所有请求共有的协议、网址、端口等信息的&#xff1b;通常情况下&#xff0c;一批量的接口测试&#xff0c;访问的是同一个站点&#xff0c;那么以上信息基本都是相同的&#xff0c;就不需要在每个请求中重复编写&#xff1b; 每个请…

Spring cloud - Hystrix源码

其实只是Hystrix初始化部分&#xff0c;我们从源码的角度分析一下EnableCircuitBreaker以及HystrixCommand注解的初始化过程。 从EnableCircuitBreaker入手 我们是通过在启动类添加EnableCircuitBreaker注解启用Hystrix的&#xff0c;所以&#xff0c;源码解析也要从这个注解…

2014年5月28日 Go生态洞察:GopherCon 2014大会回顾

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

ansible的基本安装

目录 一、简介 1.ansible自动化运维人工运维时代 2.自动化运维时代 3.ansible介绍 4.ansible特点 二、ansible实践 1.环境 2.ansible管理安装 3.ansible被管理安装 4.管理方式 5.添加被管理机器的ip 6.ssh密码认证方式管理 三、配置免密登录 1.ansible自带的密码…

hp惠普Victus Gaming Laptop 15-fa1025TX/fa1005tx原装出厂Win11系统ISO镜像

光影精灵9笔记本电脑原厂W11系统22H2恢复出厂时开箱状态一模一样 适用型号&#xff1a;15-fa1003TX&#xff0c;15-fa1005TX&#xff0c;15-fa1007TX&#xff0c;15-fa1025TX 链接&#xff1a;https://pan.baidu.com/s/1fBPjed1bhOS_crGIo2tP1w?pwduzvz 提取码&#xff1a…

【华为OD题库-033】经典屏保-java

题目 DVD机在视频输出时&#xff0c;为了保护电视显像管&#xff0c;在待机状态会显示"屏保动画”&#xff0c;如下图所示,DVD Logo在屏幕内来回运动&#xff0c;碰到边缘会反弹:请根据如下要求&#xff0c;实现屏保Logo坐标的计算算法 1、屏幕是一个800 * 600像素的矩形&…

软件测试:功能测试常用的测试用例大全

登录、添加、删除、查询模块是我们经常遇到的&#xff0c;这些模块的测试点该如何考虑 1)登录 ① 用户名和密码都符合要求(格式上的要求) ② 用户名和密码都不符合要求(格式上的要求) ③ 用户名符合要求&#xff0c;密码不符合要求(格式上的要求) ④ 密码符合要求&#xf…

JavaScript实现右键菜单

1、代码实现 window.onload function () {(function () {// 自定义右键菜单内容并插入到body最后一个节点前let dom <div id"rightMenuBars"><div class"rightMenu-group rightMenu-small"><div class"rightMenu-item"><…

【应用程序启动过程-三种加载控制器的方式-上午内容复习 Objective-C语言】

一、我们先来回忆一下,上午所有内容 1.首先呢,我们先说的是这个“应用程序启动过程”, 应用程序启动过程里面,有三方面内容 1)UIApplication对象介绍 2)AppDelegate对象介绍 3)应用程序启动过程 现在不知道大家对这个应用程序启动过程有印象吗, 2.首先,这个UIAp…