(二一)SQL优化

2023-11-09

insert优化

批量插入

insert into tb_name values
    (col_1, ..., col_n),
    ...;

手动提交事务

start transaction;
insert into tb_name values ...;
commit;

主键顺序插入(主键优化)

主键顺序插入的性能高于乱序插入(会发生页分裂)。

数据组织方式

在lnnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表(index organized table lOT)。

页分裂

页可以为空,也可以填充一半,也可以填充100%。每个页包含了2~N行数据(如果一行数据多大,会行溢出),根据主键排列。

页合并

当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并它的空间变得允许被其他记录声明使用。

当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),nnoDB会开始寻找最靠的页前或后)看看是否可以将两个页合并以优化空间使用。

主键设计原则

  1. 满足业务需求的情况下,尽量降低主键的长度
  2. 插入数据时,尽量选择顺序插入,选择使用AUTOINCREMENT自增主键。
  3. 尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
  4. 业务操作时,避免对主键的修改。

大批量插入数据:load

如果一次性需要导入大批量数据,用insert插入性能较低,可以采用load插入。

# 客户端连接服务器时,加上参数 --local-infile
mysql --local-infile -u root -p

set global local_infile = 1;

load data local infile '文件路径' 
into table tb_user
fields terminated by ','
lines terminated by '\n';

创建一个数据库,并建立需要导入数据的表结构。

create database test;
use test;
CREATE TABLE tb_user(
	id INT NOT NULL AUTO_INCREMENT
    , username VARCHAR(50) NOT NULL
    , password VARCHAR(50) NOT NULL
    , name VARCHAR(20) NOT NULL
    , birthday DATE DEFAULT NULL
    , sex CHAR(2) DEFAULT NULL
	, PRIMARY KEY (id)
	, UNIQUE KEY unique_user_username(username)
) ENGINE = INNODB DEFAULT CHARSET = utf8;

准备sql脚本数据 tb_user.sql(我一般把数据文件放在C:\ProgramData\MySQL目录下,不容易出错,谨慎尝试数据量巨大的导入,会导致磁盘爆满,我后面没有办法重装系统才好)。(csv文件同理)

脚本数据的结构

导入sql脚本(注意路径中是“/”):

-- sql脚本
load data infile 'C:/ProgramData/MySQL/tb_user.sql'
into table tb_user
fields terminated by ','
lines terminated by '\n';


-- csv文件
load data infile 'C:/ProgramData/MySQL/tb_user.csv'
into table tb_user
fields terminated by ','
lines terminated by '\r\n';

如果出现 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement ,找到my.ini文件(一般在C:\ProgramData\MySQL\MySQL Server 8.0 目录下)打开,在文末添加 secure_file_priv='' 保存,然后停止mysql再启动mysql((二)MySQL的安装、启动/停止/连接、卸载

order by 优化

  1. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
  2. 尽量使用覆盖索引。
  3. 多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
  4. 如果不可避免的出现filesort,大数据排序时,可以适当增大排序缓冲区大小 sort buffer size(默认256k)。
  1. Using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sotbuffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。(性能较低)
  2. Using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高。
-- 根据country表中的name, gnp进行降序一个升序,一个降序(表中已创建idx_country_name_gnp索引)
explain select code, name, gnp from country order by name asc, gnp desc;

这个时候会出现 using index和using filesort,因为创建索引时,默认为asc。

-- 创建索引 
create index idx_country_name_gnp_ad on country(name asc, gnp desc);

explain select code, name, gnp from country order by name asc, gnp desc;

此时就只会出现using index,性能得到提升。

group by 优化 

use test;
explain select continent, count(*) from country group by continent;

在country表只有一个主键索引时,直接对continent进行group by,会出现using temporary,此时性能较低。

create index idx_country_continent_region on country(continent, region);
explain select continent, count(*) from country group by continent;

创建idx_country_continent_region索引后,对continent进行group by,不出现using temporary;

explain select region, count(*) from country group by region;

直接对region进行group by,会出现using temporary,因为不满足最左前缀法则;

explain select continent, region, count(*) from country group by continent, region;

同时对continent, region进行group by,不出现using temporary;

explain select region, count(*) from country where continent = 'europe' group by region;

加入continent过滤后,不出现using temporary,满足最左前缀法则;

limit 优化

一个常见又非常头疼的问题就是 limit 2000000,10 ,此时需要MySOL排序前2000010 记录,仅仅返回2000000 -2000010的记录,其他记录丢弃,查询排序的代价非常大。

优化思路:一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引+子查询形式进行优化。

explain select * from tb sku t , (select id from tb sku order by id limit 2000000,10) a where t.id = a.id:

count优化

  • MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高
  • InnoDB 引擎执行 count(*)的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。

优化思路:自己计数

count的几种用法

count是一个聚合函数,对于返回的结果集,一行行地判断,如果ount 函数的参数不是 NULL,累计值就加1,否则不加,最后返回累计值。

用法:count (*)、count (主键)、count (字段)、count (1)

count(主键):InnoDB引擎会遍历整张表,把每一行的 主键id 值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加(主键不可能为null).

count (字段):没有not nul 约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,服务层判断是否为nul,不为nul,计数累加有not null 约束:lnnoDB 引警会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行进行累加。

count (1):lnnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加。

count (*):InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。

按照效率排序的话,count(字段)< count(主键 id)< count(1)= count(*),所以尽量使用 count(*)。

update 优化

  • 在使用update进行更新数据时,要避免以没有索引的列为条件,这样在执行事务的时候,行级锁会升级为表级锁,会锁住整张表,这样执行的性能就会降低
  • 此外,如果索引失效,行锁也会升级为表锁。

Innodb特点:事务,外键,行级锁。Innodb是对索引加的行锁,不是对记录加的。

首先在A窗口中开启一个事务,先不提交

--------------------------窗口A-------------------------------

use world;

begin;

select * from city;

-- 执行update语句, 此时id=1的行锁定
update city set name = 'new_name_1' where id = 1; 

再在窗口B同时开启一个事务:

--------------------------窗口B-------------------------------

use world;

begin;

select * from city;

-- 执行update语句,id=4可以执行成功
update city set name = 'new_name_2' where id = 4;

分别提交:

commit;

现象分析:窗口A和B都能执行成功的原因是,id字段有索引,上锁的时候上的是行级锁。且update语句中的条件不同(id=1和id=4),互不影响,故能够执行成功。

如果update语句中的条件字段没有索引呢?即使条件不同,也有影响,不能同时执行,因为上的是表锁,锁定了整张表。只有窗口A提交之后,窗口B才能执行。

--------------------------窗口A-------------------------------

use world;

begin;

select * from city;

-- 执行update语句, name没有索引,则上的是表锁
update city set name = 'new_name_1' where name = 'Kabul'; 
--------------------------窗口B-------------------------------

use world;

begin;

select * from city;

-- 执行update语句, 不能执行成功,因为表被锁定了
update city set name = 'new_name_2' where name = 'Mazar-e-Sharif';

不总结=白学 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(二一)SQL优化 的相关文章

  • 使用条件 SQL 统计每月汇总记录

    我有一张桌子 我们就叫他们桌子吧SUMMARYDATA NIP NAME DEPARTMENT STATUSIN STATUSOUT TOTALLOSTTIME A1 ARIA BB 2020 01 21 08 06 23 2020 01
  • 如何计算 Postgres 上图表中所有连接的节点(行)?

    我的桌子有account id and device id One account id可以有多个device ids 反之亦然 我正在尝试计算每个连接的多对多关系的深度 Ex account id device id 1 10 1 11
  • 如何进行数据透视并计算列平均值

    我承认这是迄今为止我必须面对的最复杂的 SQL 语句之一 我在这件事上碰壁了 我希望有人能帮我一把 我在数据库中有这张表 Item ActiveTime sec DateTime 1 10 2013 06 03 17 34 22 gt Mo
  • 自动提取数据 - Oracle SQL Developer

    我通过 SQL Developer 连接到 Oracle 数据库 我想编写一个返回每月数据集的查询 然后将该数据提取到分隔文本文件中 我知道如何做到这一点就好了 我想知道是否有一种方法可以编写一个脚本来运行查询并在一年内逐月提取数据 这样我
  • 在 Mysql 上使用 EntityManager JPA 运行脚本

    我正在尝试运行脚本 sql 文件 但由于我尝试了多种方法 因此出现多个错误 这是我的主要 sql 脚本 INSERT INTO Unity VALUES 11 paq 0 2013 04 15 11 41 37 Admin Paquete
  • 在 MS Access SQL 查询中从正常日期转换为 unix 纪元日期

    我正在尝试编写一个通过 ODBC 连接到 MySQL 数据库的 MS Access 2007 连接的查询 一切工作正常 查询执行我想要的操作 我挂断的部分是我一直在询问用户 unix 纪元时间 而不是常规日期 我查找了 MS Access
  • 标量子查询包含多行

    我正在使用 H2 数据库并想要移动一些数据 为此 我创建了以下查询 UPDATE CUSTOMER SET EMAIL SELECT service EMAIL FROM CUSTOMER SERVICE AS service INNER
  • 需要 SQL 查询澄清[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有一个由以下列组成的表 billid patientid doctorid fees 如何显示治疗多名患者的医生 尝试了以下代码并得到了
  • 包含列和行总计的 SQL 数据透视表

    我正在尝试将行和列总计添加到该数据透视表中 create table test4 city nvarchar 10 race nvarchar 30 sex nvarchar 10 age int insert into test4 val
  • 如何使用原始 SQL 查询实现搜索功能

    我正在创建一个由 CS50 的网络系列指导的应用程序 这要求我仅使用原始 SQL 查询而不是 ORM 我正在尝试创建一个搜索功能 用户可以在其中查找存储在数据库中的书籍列表 我希望他们能够查询 书籍 表中的 ISBN 标题 作者列 目前 它
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 更改mysql数据库表中的日期格式

    大家早上好 只是一个简单的问题 在我现有的 MySql 数据库中 我几乎没有包含日期 的列 目前这些是年 月 日格式 但现在我需要将其全部更改为年 月 日格式 我试过了select date format curdate d m Y 但它不
  • 在Oracle中使用IW和MM

    我使用 IW 表示每周结果 使用 MM 表示每月结果 但我总是收到错误 ORA 00979 not a GROUP BY expression 00979 00000 not a GROUP BY expression 我的疑问是这些 We
  • SQL查询查找具有特定数量关联的行

    使用 Postgres 我有一个架构conversations and conversationUsers Each conversation有很多conversationUsers 我希望能够找到具有确切指定数量的对话conversati
  • 可以有一个带有可变列的表吗?

    这可能是一个愚蠢的问题 但这里是 是否可以创建一个能够包含具有可变列数和自定义列名称的行的动态表 我浏览过 EAV 建模 但看起来很沉重 现实生活中的例子可能是这样的 假设我有一个客户登记册 但每个客户可能需要输入不同的信息 根据您要输入的
  • 如何创建没有循环关系的树形表?

    CREATE TABLE TREE node1 id UUID REFERENCES nodes object id NOT NULL node2 id UUID REFERENCES nodes object id NOT NULL CO
  • SQL:如何从一个表中获取另一个表中每一行的随机行数

    我有两个数据不相关的表 对于表 A 中的每一行 我想要例如表 B 中的 3 个随机行 使用光标这相当容易 但速度非常慢 那么我该如何用单个语句来表达这一点以避免 RBAR 呢 要获得 0 到 N 1 之间的随机数 可以使用 abs chec
  • SQL Server 查询中 UNION ALL 与 OR 条件

    我必须根据表上不存在的条件选择一些行 如果我使用如下的 union all 它会在不到 1 秒的时间内执行 SELECT 1 FROM dummyTable WHERE NOT EXISTS SELECT 1 FROM TABLE t WH
  • 无法与重定向器建立连接。确保“sql browser”服务正在运行

    所以我尝试这个 sql server 2012 由于这个错误我无法打开任何 ssis 包 无法与重定向器建立连接 确保 sql browser 服务正在运行 我的 Sql 浏览器肯定正在运行 我尝试在本地服务 本地系统和网络下更改它 仍然没
  • 需要在 SQL Server 中透视字符串值

    我有一个包含值的表 描述为 Occupation String Name String Developer A Developer B Designer X Coder Y Coder Z 我需要数据透视格式的值 Designer Deve

随机推荐

  • 【已成功解决】使用vpn/代理后无法正常上网/无法正常访问网站

    文章目录 一 问题描述 二 解决步骤 三 原因分析 一 问题描述 很多同学在学习访问学校提供的资源时或者一些小伙伴在公司办公时需要使用VPN 但是当我们关闭VPN后 却发现没有办法正常连接到互联网了 可以尝试以下方法解决 至于导致这种情况发
  • ANSI是个啥???

    来自 https blog csdn net imxiangzi article details 77370160 http www cnblogs com malecrab p 5300486 html 用Notepad 创建一个文本文件
  • 解决Android 8.1 获取不到wifi名称

    在安卓8 1版本中 用 WifiInfo getSSID 可能出现 unknown ssid 或者什么也没读出来 解决方案 用ConnectivityManager 这个类解决 代码如下 获取SSID param return WIFI 的
  • 前端传JSON嵌套类,且属性名首字母大写时后端接收的一些坑

    因为开发腾讯云业务 要写一个回调函数 规范文档上说会传一个json传给我 EventType ComposeMediaComplete ComposeMediaCompleteEvent TaskId 1256768367 ComposeM
  • stm32局部变量过大,导致栈溢出

    在做一个以stm32为主控的项目时发现自己程序中一个机构体里面的数据总是一运行就被改变 刚开始以为是自己不小心在哪个地方用了extern扩展了变量的作用域 重新赋了值 自己忘记了 后来查找了好久都没有其他地方使用这个结构体变量 于是开始单步
  • 配置文件及其解析

    配置文件 properties xml 配置文件可以解决我们在编程中遇到的硬编码问题 那么什么是硬编码呢 硬编码 将一些经常调用修改的数据代码直接写死在了java源代码程序中 就会产生硬编码问题 一般情况下 通过配置文件来解决硬编码问题 在
  • 在vue3中使用codemirror

    文章目录 前言 引入 在vue3中使用 基本配置 更改编辑框的外部样式 高度 宽度 获取和修改内容 添加删除事件 实现markdown过程中遇到的bug 前言 最近为了完成学校的大作业 需要制作markdown编辑器 为了用户输入方便 使用
  • MyBatis 配置 typeAliases 详解

    0x00 前言参考 之前的 MyBatis 中 SqlMapConfig 配置文件详解 记了一下 MyBatis 中的核心配置文件各个标签的作用和使用场景 这篇文章细说一下配置文件中 typeAliases 标签的详细使用 0x01 标签介
  • FOXBORO FBM233 电源模块

    FOXBORO FBM233 是一种电源模块 通常用于工业自动化和控制系统中 为其他设备和模块提供所需的电源供应 以下是可能与这种电源模块相关的一些常见功能 电压输出 FBM233 电源模块通常提供稳定的电压输出 以供其他设备和模块使用 这
  • 把握机器人教育朝AI智能化发展的趋势

    一般机器人是指不具有智能 只具有一般编程能力和操作功能的机器人 到目前为止 在世界范围内还没有一个统一的智能机器人定义 大多数专家认为智能机器人至少要具备以下三个要素 一是感觉要素 用来认识周围环境状态 二是运 动要素 对外界做出反应性动作
  • 百度网盘PC端扫描二维码登录时无法加载二维码问题解决方法

    问题 今天在PC端扫描登录百度网盘时 二维码无法加载出来 具体情况如图 解决方法 1 打开IE浏览器 2 打开工具 3 打开Internet选项 4 打开高级选项 重置IE设置 5 点击确定 打开百度网盘 重新扫描登录 写在后面 好了 现在
  • 基于机器学习之模型树短期负荷预测(Matlab代码实现)

    欢迎来到本博客 目前更新 电力系统相关知识 期刊论文 算法 机器学习和人工智能学习 支持 如果觉得博主的文章还不错或者您用得到的话 可以关注一下博主 如果三连收藏支持就更好啦 这就是给予我最大的支持 本文目录如下 目录 1 概述 2 数学模
  • 家庭记账本小程序之删(java web基础版四)

    实现删除消费账单 1 main left jsp中该部分 调用Servlet中delete方法 2 Servlet中delete方法 调用Dao层list方法 跳转到del jsp页面 3 Dao层list方法 4 del jsp 调用Se
  • Unity动画状态机Animator使用解析

    Unity可以用两种方式控制动画 1 Animations 这种方式简单 直接 Play Idle 或者 CorssFade Idle 就可以播放动画 2 Animator 5 x之后推荐使用这种方式 因为里面可以加上混合动画 让动画切换更
  • mysql 添加用户、修改权限,修改登陆权限ip

    MySQL 赋予用户权限命令的简单格式可归纳为 数据库 grant 权限 on 数据库对象 to 用户 1 grant 普通数据用户 查询 插入 更新 删除 数据库中全部表数据的权利 apache grant select on testd
  • SpringBoot(审计) 统计接口调用次数及成功率

    介绍 很多时候会需要提供一些统计记录的 比如某个服务一个月的被调用量 接口的调用次数 成功调用次数等等 优点 使用AOP Hendler对业务逻辑代码无侵入 完全解耦 通过spring boot自带的健康检查接口 health 方便 安全
  • 吐血整理!内部包含3980大数据、机器学习、推荐系统实战课程,仅分享一次

    在最近几年 大数据 Dig Data 机器学习 Machine Learning 逐渐流行开来 容易让人误以为机器学习并不难 机器学习的流行原因很简单 在一个消费者 以及广告主 需要更多个性化 而计算机系统正被四面八方飞速增长的数据包围的年
  • B树及其变种

    B 树 B 树 B树
  • L6050U compile erro

    L6050U The code size of this image exceeds the maximum allowed for this version of the linker 原因 是 用的 是 EVb版本 需要 正版 才没有
  • (二一)SQL优化

    insert优化 批量插入 insert into tb name values col 1 col n 手动提交事务 start transaction insert into tb name values commit 主键顺序插入 主