MYSQL sql的技巧与避坑

文章目录

      • 1.使用union还是or
      • 2.可以为NULL字段的逻辑判断
      • 3.in和exists的选择
      • 4.if和case的使用
      • 5.删除表中重复的记录,只保留id最小的
      • 6.字符串函数
      • 7.group_concat 批量连接
      • 8.rlike 正则模糊查询
      • 9.ifnull
      • 10.日期函数
      • 11.大表分页查询
      • 12.索引不生效的经典场景
      • 13.订单最多的客户
      • 14.in查询慢的原因
      • 15.主键索引和普通索引
      • 16.where条件中有多个二级(普通)索引,如何优化?
      • 17.limit分页,普通索引转主键索引,避免回表
      • 18.where order_id = ? order by id asc limit n
      • 19.CPU飙升超过100%怎么办?

1.使用union还是or

由于sql中只能用到一个index,如果or的两边是同一个字段,可以用上索引,如果是不同的字段,势必有一个字段全表扫描。union替代or可以使不同字段都用上索引,但是union会对数据进行去重和排序,性能不一定比用or好。但是如果是没有去重要求的数据,可以union all,不去重且不排序,性能就比较好了。

2.可以为NULL字段的逻辑判断

MySQL 使用三值逻辑 —— TRUE, FALSE 和 UNKNOWN。任何与 NULL 值进行的比较都会与第三种值 UNKNOWN 做比较。这个“任何值”包括 NULL 本身!这就是为什么 MySQL 提供 IS NULL 和 IS NOT NULL 两种操作来对 NULL 特殊判断。

比如查询other_id不为2的记录,other_id可以为NULL,那么where other_id != 2查询出来的记录可能比实际少,因为NULL值记录是UNKNOWN的,不进入ResultSet, 应该使用other_id != 2 or other_id is NULL。

3.in和exists的选择

查询A表中a_id等于B表中b_id的所有A记录。


in 的原理:先执行in中的子查询,再与外表做笛卡尔积。in的子查询只会执行一次,便把结果集缓存到内存中
select * from A where id in (select id from B)

等价于:先select id from B; 再 select id from A where A.id = B.id;

in 只能针对主查询使用索引,not in 则不会使用任何索引。


exists 的原理:遍历外表中的数据,每一个id带入exists子查询中看是否成立,假设A有n条记录,相当与执行了n次exists子查询。exists直返会true和false,因此select 1就可以。

等价于:
select id from A; 再select id from B where B.id = A.id;

exists 会针对子查询的表使用索引;not exists 会对主子查询都会使用索引;


总结:

  • in适合外表数据量远大于内表的情况。
  • exists适合外表数据远小于内表的情况。
  • not exists由于可以用上索引,不管哪种情况,都比not in要快。

总体来说,小表驱动大表,in的时候内表是驱动表,exists的时候外表是驱动表

补充:
如果是括号内查询语句耗时,且查询结果集数量小时,用in合适,如果查询语句简单并且查询结果集大时,用exist合适。

4.if和case的使用

写出一个SQL 查询语句,计算每个雇员的奖金。如果一个雇员的id是奇数并且他的名字是以’M’开头,那么他的奖金是他工资的100%,如果一个雇员的id是奇数并且他的名字是以’N’开头的,那么他的奖金是50%,否则奖金为0。(%2或mod判断奇偶数)


if形式:

select employee_id, 
IF(employee_id%2 = 1 and name like ‘M%’, salary, IF(employee_id%2 = 1 and name like ‘N%’, salary / 2, 0)) as bonus  from Employees order by employee_id;


case形式:

select employee_id, 
(CASE 
WHEN mod(employee_id,2) = 1 and name like ‘M%’ THEN salary 
WHEN mod(employee_id,2) = 1 and name like ‘N%’ THEN salary / 2
ELSE 0 
END) as bonus  from Employees order by employee_id;

5.删除表中重复的记录,只保留id最小的

写一个SQL删除语句,将email重复的记录删除,只保留id最小的

DELETE p1 FROM Person p1,
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id

6.字符串函数

1.concat() 将多个字符串拼接
2.left(str, length) 从左开始截取字符
3.right(str, length) 从右开始截取字符
4.upper(str) 所有字符转成大写
5.lower(str) 所有字符转成小写
6.substring(str, begin, end) 或 substring(str, begin)

7.group_concat 批量连接

表 Activities:

±------------±--------+
| 列名 | 类型 |
±------------±--------+
| sell_date | date |
| product | varchar |
±------------±--------+
此表没有主键,它可能包含重复项。
此表的每一行都包含产品名称和在市场上销售的日期。

编写一个 SQL 查询来查找每个日期、销售的不同产品的数量及其名称。每个日期的销售产品名称应按词典序排列。返回按 sell_date 排序的结果表。

解:
select
    sell_date,
    count(distinct product) num_sold,
    group_concat(
        distinct product
        order by product
        separator ‘,’
    ) products
from 
    Activities
group by sell_date

8.rlike 正则模糊查询

如果表中有多个值以空格隔开,找出包含以’NM’开头值的记录
解:select * from a where value rlike ‘^NM|.* \sNM’;

9.ifnull

Employee 表:
±------------±-----+
| Column Name | Type |
±------------±-----+
| id | int |
| salary | int |
±------------±-----+
id 是这个表的主键。
表的每一行包含员工的工资信息。

编写一个 SQL 查询,获取并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null 。

解:

SELECT
IFNULL(
(SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET 1),
NULL) AS SecondHighestSalary

10.日期函数

1.DATE(date)

返回指定日期/时间表达式的日期部分或将文本转为日期格式
示例:

select date(“2022-3-15”);2022-03-15

select date(‘2022-4-15 12:30:48’);2022-04-15

2.YEAR(date)

返回指定日期的年份(范围在1000到9999)
示例:

select year(‘2022-4-15 12:30:48’);2022

类似的,MONTH(date)返回指定日期的月份(范围在1到12);DAY(date)返回指定日期的日(范围在1到31);HOUR(datetime)返回指定时间的小时(范围在0-23);minute(datetime)返回指定时间的分(范围在0-59);second(datetime)返回指定时间的秒(范围在0-59)。

3.对日期进行加减运算

ADDDATE(date,interval expr type)
DATE_ADD(date,interval expr type)
SUBDATE(date,interval expr type)
DATE_SUB(date,interval expr type)

其中,date是一个datetime或date值;expr是对date进行加减法的一个表达式字符串或一个数字;type指明表达式expr应该如何被解释,是减去1天还是一年等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zdn6WrD1-1689158507889)(evernotecid://CF273F2A-DFE6-4438-B24E-1642BCBC2DAC/appyinxiangcom/39628498/ENResource/p113)]

示例:
select adddate(‘2022-4-1’,interval 5 day);2022-04-06

select adddate(‘2022-4-15 13:30:28’,interval ‘3 1:2’ day_minute);2022-04-18 14:32:28

4.DATE_FORMAT(date, format)

根据format字符串格式化date值,常用于获取日期的年月日和时间

在format字符串中可用标志符
%M 月名字(january……december)
%Y 年, 数字, 4 位
%y 年, 数字, 2 位
%a 缩写的星期名字(sun……sat)
%d 月份中的天数, 数字(00……31)
%e 月份中的天数, 数字(0……31)
%m 月, 数字(01……12)
%c 月, 数字(1……12)
%b 缩写的月份名字(jan……dec)
%j 一年中的天数(001……366)
%h 十二时制的小时(00……12)
%k 二十四时制的小时(0……23)
%i 分钟, 数字(00……59)
%r 时间,12 小时(hh:mm:ss [ap]m)
%s 秒(00……59) %p am或pm
%w 一个星期中的天数(0=sunday ……6=saturday )
%u 一年中的周数(1……53)

示例:

select date_format(‘2022-4-15 13:30:28’,‘%Y-%m-%d’);2022-04-15

5.CURDATE()

以’yyyy-mm-dd’或yyyymmdd格式返回当前日期值(根据返回值所处上下文是字符串或数字)
示例:

select curdate();2022-04-15

select curdate()+0;20220415

6.CURTIME()

以’hh:mm:ss’或hhmmss格式返回当前时间值(根据返回值所处上下文是字符串或数字)
示例:
select curtime();22:26:44

7.NOW()

以’yyyy-mm-dd hh:mm:ss’或yyyymmddhhmmss格式返回当前日期时间(根据返回值所处上下文是字符串或数字
示例:

select now();2022-04-15 22:28:33

8.TIMESTAMPDIFF(type,expr1,expr2)

返回起始日expr1和结束日expr2之间的时间差整数。

时间差的单位由type指定:
second 秒
minute 分
hour 时
day 天
month 月
year 年

示例:

select timestampdiff(day,‘2022-4-1’,‘2022-4-15’) 14

9.DATEDIFF(date1, date2)
返回 date1 - date2 的天数

10.UNIX_TIMESTAMP([date])

返回一个unix时间戳(从’1970-01-01 00:00:00’开始的秒数,date默认值为当前时间)
示例:

select unix_timestamp(‘2022-4-15’);1649952000

11.FROM_UNIXTIME(unix_timestamp)

以’yyyy-mm-dd hh:mm:ss’或yyyymmddhhmmss格式返回时间戳的值(根据返回值所处上下文是字符串或数字)

示例:

select from_unixtime(1649952001);2022-04-15 00:00:01

11.大表分页查询

https://blog.csdn.net/w907645377/article/details/122234432

12.索引不生效的经典场景

特别容易忽视的:
1.where使用的索引与order by使用的索引一致或为联合索引,order by才可能用上索引
2.不同表utf8和ut8mb4字段连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHcEzou9-1689158507889)(evernotecid://CF273F2A-DFE6-4438-B24E-1642BCBC2DAC/appyinxiangcom/39628498/ENResource/p114)]

13.订单最多的客户

表: Orders

±----------------±---------+
| Column Name | Type |
±----------------±---------+
| order_number | int |
| customer_number | int |
±----------------±---------+
Order_number是该表的主键。
此表包含关于订单ID和客户ID的信息。

编写一个SQL查询,为下了 最多订单 的客户查找 customer_number 。测试用例生成后, 恰好有一个客户 比任何其他客户下了更多的订单。

解:
SELECT
    customer_number
FROM
    orders
GROUP BY customer_number
ORDER BY COUNT(1) DESC
LIMIT 1
;

14.in查询慢的原因

见下面的链接:
https://blog.csdn.net/w907645377/article/details/123129383

15.主键索引和普通索引

  • 主键索引的优先级高于普通索引
  • 主键索引及其他唯一索引,使用in可能导致索引失效,具体看14
  • 一条查询语句只能用上一个普通索引
  • order by 主键 可以搭配 where 任意普通索引 使用
  • 如果order by 普通索引一 搭配 where 普通索引二使用,可以考虑建立 普通索引一和普通索引二的联合索引

16.where条件中有多个二级(普通)索引,如何优化?

where条件中的多个索引来自同一张表:
可以考虑联合索引,mysql自身也会mergeIndex,但这意味着索引设计不合理

where条件中的多个索引来自不同表:
比如a join b,或 a exists b等,可以考虑b表使用子查询,将非连接列的索引使用上,得到的子查询结果c,再与a表进行连接,这样可以用上尽量多的索引

17.limit分页,普通索引转主键索引,避免回表

比如:我们要分页查询状态为5的订单

一般写法:
select * from order where status = 5 limit 20000,20;
缺点:查询订单表的所有字段,通过status查询到主键id后,需要回表,主要问题是limit比较大,limit的原理是查出20000 + 20条,然后扔掉前20000条,这就意味着要回表20020次, 十分耗时

主键索引优化写法:
select * from order o1, (select id from order where status = 5 limit 20000, 20) o2 where o1.id = o2.id;
优点是不用回表了,但是依然有扫描20000 + 20条

更优化的写法,使用id分页,加一个查询条件 id >= minId,这次的最后一条id + 1,作为下一次分页的minId
这个链接也有类似介绍
https://blog.csdn.net/S_ZaiJiangHu/article/details/125821319

18.where order_id = ? order by id asc limit n

这条sql,看上去应该会使用order_id的索引,实际上当n很小的时候,优化器考虑扫码id索引树(全表扫描)可能比使用order_id的索引更快,最终使用了id索引。
优化:
1.强制索引
2.where order_id = ? order by (id+0) asc limit n; 骗过优化器,使用order_id的索引

19.CPU飙升超过100%怎么办?

首先,我们要对问题定位而不是盲目的开启什么 慢日志,在并发量大并且大量SQL性能低的情况下,开启慢日志无意是将MySQL推向崩溃的边缘。

1.不推荐在这种CPU使用过高的情况下进行慢日志的开启。因为大量的请求,如果真是慢日志问题会发生日志磁盘写入,性能贼低。
2.直接通过MySQL show processlist命令查看,基本能清晰的定位出部分查询问题严重的SQL语句,kill 掉这些线程(同时观察 cpu 使用率是否下降), 一般来说,肯定要 kill 掉这些线程(同时观察 cpu 使用率是否下降),进行相应的调整(比如说加索引、改 sql、改内存参数)之后,再重新跑这些 SQL。
3.再则一定要使用缓存系统,降低对MySQL的查询频次。
4.对于内存调优,也是一种解决方案。

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

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

相关文章

2023年11月软考中级信息系统监理师如何报名考试?

信息系统监理师就是要借鉴建筑工程监理的管理模式,经过研究开始启动建立我国信息工程监理制度。是信息管理(信息管理培训)中非常不错的一个职业,作为一个制度的建立,首先要产生监理机构,就是有符合要求的监…

Kafka消息监控管理工具Offset Explorer的使用教程

1、kafka监控管理工具 Offset Explorer是一款用于监控和管理Apache Kafka集群中消费者组偏移量的开源工具。它提供了一个简单直观的用户界面,用于查看和管理Kafka消费者组偏移量的详细信息。 Offset Explorer具有以下主要功能和特点: 实时监控&#x…

架构训练营学习笔记3-5:消息队列备选架构设计实战

本文属于架构训练营学习笔记系列:模块3的案例讲解 总的来说,这篇从更高的维度去讲,而不是关注消息队列的常见问题:比如消息如何发送,消息如何不丢失 ,消息如何不重复。总体上分为2部分:利益干系…

vue-使用ElementPlus搭建系统

详尽的搭建过程可以参考 📚使用ElementPlus页面布局搭建 本章只提取重要且常用部分 Container 布局容器 Layout 布局 Dropdown 下拉菜单 Menu 菜单 -》 动态菜单显示 -》动态router 实现菜单折叠效果

临时文档章

内部类的分类有哪些 内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。 静态内部类 定义在类内部的静态类,就是静态内部类。 public class Outer {private static int radius 1;static class StaticInner {public void visit()…

【Docker】什么是Docker,它用来干什么

作者简介: 辭七七,目前大一,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖&#x1f…

ADB初识

ADB是Android Debug Bridge,是一个命令行程序。abd可以从计算机上通过USB控制Android手机设备。可以使用ADB复制文件、安装和卸载应用程序,运行shell命令等。 ADB的下载配置 Windows版本:https://dl.google.com/android/repository/platform…

2.SpringBoot运维实用篇

SpringBoot运维实用篇 ​ ​ 下面就从运维实用篇开始讲,在运维实用篇中,我给学习者的定位是玩转配置,为开发实用篇中做各种技术的整合做好准备工作。 主要分为以下内容: SpringBoot程序的打包与运行配置高级多环境开发日志 ​…

C国演义 [第十二章]

第十二章 打家劫舍题目理解步骤dp数组递推公式初始化遍历顺序 代码 打家劫舍II题目理解步骤递推公式初始化遍历顺序 代码 打家劫舍 力扣链接 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋…

《深度学习推荐系统》笔记

目录 一、推荐系统是什么1.作用和意义2.推荐系统的架构2.1 逻辑架构2.2 技术架构 二、传统的推荐系统方法1. 协同过滤算法1.1 userCF&&ItemCF1.3 矩阵分解算法 2. 逻辑回归算法3. 因子分解机3.1 POLY2模型3.2 FM模型3.3 FFM模型3.4 小结 4. 组合模型4.1 GBDTLR组合模型…

通过监控平台提高运维效率、降低运营成本、实现绿色低碳、节能降耗、提升PUE值-安科瑞黄安南

01引言 近年来,随着母线槽在建筑及工厂的配电中越来越广泛,母线槽场景运用得越多,随着数据中心建设的快速发展和更高需求,智能母线系统逐渐被应用于机房的末端配电中,具有电流小、插接方便、智能化程度高等特点&#…

K8s的介绍(2)

K8s是一个开源的,用于管理云平台中多个主机上的容器化的应用,K8s的目标是用来管理云平台中多个主机上的容器化的应用,k8s是让部署容器化的应用简单且高效。 k8s的特性 (1)自动装箱:基于容器对应用运行环境…

中间件上云部署 zookeeper

中间件上云部署 zookeeper 企业级中间件上云部署 zookeeper一、环境说明二、zookeeper部署YAML资源清单准备三、zookeeper部署及部署验证四、zookeeper应用验证 企业级中间件上云部署 zookeeper 一、环境说明 storageclassingress 二、zookeeper部署YAML资源清单准备 # vim…

【OC总结- Block】

文章目录 前言2. Block2.1 Block的使用规范2.2 __block修饰符2.3 Block的类型2.4 Block的循环引用及解决循环引用的场景引入解决循环引用Block循环引用场景 2.5 Block的实现及其本质2.5.1 初始化部分2.5.2 调用部分2.5.3 捕获变量 Block本质2.6 Block捕获变量 和 对象2.7 Block…

数据结构-双向带头循环链表

链表的分类实现带有哨兵位的双向的循环链表**定义节点的结构**初始化单个节点初始化带有哨兵位的双向循环链表打印链表销毁链表尾插尾删头插头删find函数在任意位置之前插入任意位置的删除全部代码list.hlist.ctest.c 链表和顺序表的区别 链表的分类 如下 根据上述的三种组合…

一个月学通Python(十八):Django表单的应用(Web开发)

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3章,1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍表单的应用表单的应用 我们继续来完成上一章节中…

部署langchain+chatglm

先参考:window零基础部署langchain-ChatGLM_飞奔的屎壳郎的博客-CSDN博客 安装一部分, 1.GCC安装 gcc64位下载 一定要装64位的gcc,因为我的电脑是w10 64位的,装32位运行langchain报错并配置环境变量 可直接用压缩包中的文件&am…

Verilog 学习之路

循环 7-10 代码段 generategenvar i;for (i0; i<8; i i1) begin: my_block_nameassign out[i] in[8-i-1];end endgenerate解释 该代码使用了 S y s t e m V e r i l o g SystemVerilog SystemVerilog 中的 g e n e r a t e generate generate 构造&#xff0c;它允许在…

mysql怎么查询慢查询,及杀死对应进

要查询和处理慢查询&#xff0c;以及杀死对应的进程&#xff0c;可以按照以下步骤进行操作&#xff1a; 1】查询慢查询&#xff1a; 在 MySQL 中&#xff0c;可以通过设置 slow_query_log 参数来启用慢查询日志&#xff0c;并配置 long_query_time 参数设置查询执行时间的阈值…

【软考】系统架构设计风格分类的个人理解

个人适当学习了软考系统架构设计师中关于系统架构设计相关的内容&#xff0c;梳理了一下相关信息。 常见架构类型和常见分类 常见的软考中出现的系统架构列举如下&#xff1a; 分层架构管道-过滤器架构客户端-服务器架构模型-视图-控制器架构&#xff0c;即MVC架构事件驱动架…