范围查询 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级别了也可以继续优化,优化的一个思路就是创建联合索引避免回表。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot宠物店管理系统-计算机毕设 附源码 32041

SpringBoot宠物店管理系统 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;宠物行业当然也不例外。宠物店管理系统是以实际运用为开发背景&#xff0c;运用软件工程原理…

python pdf转txt文本、pdf转json

文章目录 一、前言二、实现方法1. 目录结构2. 代码 一、前言 此方法只能转文本格式的pdf&#xff0c;如果是图片格式的pdf需要用到ocr包&#xff0c;以后如果有这方面需求再加这个方法 二、实现方法 1. 目录结构 2. 代码 pdf2txt.py 代码如下 #!/usr/bin/env python # -*- …

【ArcGIS Pro微课1000例】0037:ArcGIS Pro中模型构建器的使用---以shp批量转kml/kmz为例

文章目录 一、ArcGIS Pro模型构建器介绍二、shp批量转kml/kmz1. 打开模型构建器2. 添加工作空间4. 添加【创建要素图层】工具5. 添加【图层转kml】工具6. 输出文件命名7. 运行模型三、模型另存为1.py文件2. 保存为工具一、ArcGIS Pro模型构建器介绍 模型构建器是一种可视化编程…

C语言从入门到精通之【表达式和语句】

1 表达式 表达式由运算符和运算对象组成&#xff0c;最简单的表达式一个单独的运算对象。每个表达式都有一个值&#xff0c;并且是根据运算符优先级规定的顺序来执行&#xff0c;以下是一些表达式&#xff1a; 4 -6 421 a*(b c/d)/20 q 5*2 x q % 3 #q > 3 2 语句 语句…

yolov5从英伟达平台移植到华为昇腾开发板上的思路

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 最近需要将yolov5代码从英伟达平台移植到华为昇腾开发板上。搜了一些代码和资料&#xff0c;大致明白了二者的差别。 1.二者使用的模型文件不一样 yolov…

【unity实战】实现一个放置3d物品建造装修系统(附项目源码)

文章目录 最终效果前言绘制开始场景素材开始放置旋转物体扩展优化1. 绘制地图边界&#xff0c;确保放置物品在指定区域内工作2. 让模型所占面积大小更加准确3. 隐藏白色瓦片指示区域 最终效果其他源码参考完结 最终效果 前言 其实3d物品建造装修系统之前就已经做过了&#xff…

2024年天津天狮学院食品质量与安全专业《普通化学》考试大纲

2024年天津天狮学院食品质量与安全专业高职升本入学考试《普通化学》考试大纲 一、考试性质 《普通化学》专业课程考试是天津天狮学院食品质量与安全专业高职升本入学考试 的必考科目之一&#xff0c;其性质是考核学生是否达到了升入本科继续学习的要求而进行的选拔性考试。《…

[计算机网络]运输层概述

虽然我自己也不知道写在前面和前言有什么区别..... 这个系列其实是针对<深入浅出计算机网络>的简单总结,加入了一点个人的理解和浅薄见识,如果您有一些更好的意见和见解,欢迎随时协助我改正,感激不尽啦. 最近心态平和了不少, 和过去也完全做了个割舍吧,既然痛苦和压力的…

记录华为云服务器(Linux 可视化 宝塔面板)-- 安全组篇

文章目录 前言安全组说明安全组的特性安全组的应用场景 进入安全组添加基本规则添加自定义规则如有启发&#xff0c;可点赞收藏哟~ 前言 和windows防火墙类似&#xff0c;安全组是一种虚拟防火墙&#xff0c;具备状态检测和数据包过滤功能&#xff0c;可以对进出云服务器的流量…

typeof,instanceof

1.typeof typeof运算符返回的结果是以小写的字符串表示的变量的类型 2.instanceof instanceof运算符用于判断右边构造函数的原型对象是否在左边对象的原型链上 let arr[]let obj{}let datenew Dateconsole.log(arr instanceof Array)console.log(arr instanceof Object)conso…

Maven 简单配置阿里云镜像

配置步骤&#xff1a; 1、找到 maven 的安装目录&#xff0c;修改settings.xml 2、在文件中找到<mirrors>标签&#xff0c;然后再标签中添加阿里云配置即可 <mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共…

巧妙之中见真章:深入解析常用的创建型设计模式

设计模式之创建型设计模式详解 一、设计模式是什么&#xff1f;二、模板方法2.1、代码结构2.2、符合的设计原则2.3、如何扩展代码2.4、小结 三、观察者模式3.1、代码结构3.2、符合的设计原则3.3、如何扩展代码3.4、小结 四、策略模式4.1、代码结构4.2、符合的设计原则4.3、如何…

Pinctrl子系统和GPIO子系统

Pinctrl子系统&#xff1a; 借助Princtr子系统来设置一个Pin的复用和电气属性&#xff1b; pinctrl子系统主要做的工作是&#xff1a;1. 获取设备树中的PIN信息&#xff1b;2.根据获取到的pin信息来设置的Pin的复用功能&#xff1b;3.根据获取到的pin信息去设置pin的电气特性…

【机器学习 | 聚类】关于聚类最全评价方法大全,确定不收藏?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

访谈 破风之人毛京波,选择难而正确的路

“无论是在燃油时代还是电动时代&#xff0c;我们所做的一切&#xff0c;只为回归纯粹的驾驶乐趣。”履新路特斯中国总裁整整一年的毛京波&#xff0c;从不放过任何一个展示路特斯品牌驾驭精神的机会。 11月17日&#xff0c;广州车展开幕首日&#xff0c;位于5.2馆的路特斯“冠…

【理解ARM架构】 散列文件 | 重定位

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《理解ARM架构》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3d3;引出重定位&#x1f3d3;散列文件&#x1f3d3;可读可写数据段重定位&#…

OSG编程指南<十一>:OSG几何体操作及三维地形创建

1、简化几何体 在 OSG 中&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体&#xff0c;简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能 存在多种降低场景渲染效率的原…

JAVA小游戏“简易版王者荣耀”

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; im…

Scope 模块

Scope 模块可以连接任何类型的实数信号线 (不支持复数)。 波形显示界面主要包括两个部分: Scope 独有的工具栏、波形显示区域。 波形显示界面默认是黑色背景, 当有单个信号输入时, 信号线是黄色的。 Scope 模块也有菜单栏, 只不过默认将其句柄和显示都隐藏起来, 可以通过下面…