当前位置: 首页 > news >正文

SQL优化相关(持续更新)

常用sql修改

1、LIMIT 语句

在 SQL 查询中,LIMIT 10000, 10 的语句表示从第 10001 行开始,返回 10 行结果。要优化这个查询,可以考虑以下几点:

  1. 使用合适的索引:确保涉及到查询条件和排序的列上有适当的索引,这样可以加快查询的速度。
  2. 避免全表扫描:如果查询条件允许的话,尽可能添加 WHERE 子句来限制检索的行数,避免扫描整个表。
  3. 分页缓存:如果该查询是常用的翻页查询,可以考虑将结果缓存在应用程序的内存中,避免每次查询都执行数据库操作。
  4. 重构查询逻辑:如果可能的话,考虑重构查询逻辑,以减少不必要的计算或连接,从而提高查询性能。
  5. 合理设置数据库参数:根据具体的数据库系统,调整适当的参数,例如连接池大小、查询缓存等,以提高整体性能。
 eg1:
SELECT *
FROM   user
WHERE  type = 'xxx'AND name = 'xxxxx'
ORDER  BY create_time
LIMIT  1000, 10;

一般 在 type、 name、 create_time 字段上加组合索引,
在前端数据浏览翻页,或者大数据分批导出等场景下,是可以将上一页的最大值当成参数作为查询条件的
优化为:

SELECT   *
FROM     user
WHERE    type = 'xxx'
AND      name = 'xxxxx'
AND      create_time > '2017-03-16 14:00:00'
ORDER BY create_time limit 10;

eg2:

SELECT * FROM user LIMIT 10000, 10;

优化为:

SELECT * FROM user WHERE user_id >= (SELECT user_id FROM user ORDER BY user_id LIMIT 10000, 1) ORDER BY user_id LIMIT 10;

使用子查询来确定起始行的user_id,然后再以它作为过滤条件来获取接下来的10行数据。这样可以避免全表扫描,并且保持了结果的有序性。

2、隐式转换
MySQL中的隐式转换是指在表达式运算过程中,MySQL自动进行的数据类型转换而无需明确指定。隐式转换可以在不同数据类型之间进行,例如将字符串转换为数字、将日期转换为字符串等。
MySQL的隐式转换遵循一定的规则和优先级:

  1. 当使用不同的数据类型进行比较操作时,MySQL会尝试将其中一个数据类型转换成另一个数据类型,以进行比较。例如,当将一个字符串和一个数字进行比较时,MySQL会尝试将字符串转换为数字。
  2. MySQL将会自动将较低优先级的数据类型转换为较高优先级的数据类型。数据类型的优先级从低到高依次是:NULL、BIT、DATE、DATETIME、TIMESTAMP、TIME、YEAR、CHAR、VARCHAR、BINARY、VARBINARY、TINYBLOB、TINYTEXT、BLOB、TEXT、MEDIUMBLOB、MEDIUMTEXT、LONGBLOB、LONGTEXT、ENUM、SET、DECIMAL、FLOAT、DOUBLE、INT、SERIAL、BOOL、BOOLEAN。
  3. 当进行算术运算时,MySQL将会将不同的数据类型转换为相同的数据类型,然后进行计算。例如,将字符串和数字相加时,MySQL会将字符串转换为数字,然后再进行相加操作。
    需要注意的是,虽然MySQL可以进行隐式转换,但过多的隐式转换可能会导致性能下降或不准确的结果。因此,建议在编写SQL语句时明确指定数据类型,避免依赖隐式转换。
    以下是一个实际的SQL例子:
    假设有一个名为products的表,其中包含product_id(INT类型)和product_name(VARCHAR类型)两个字段。我们想查找产品ID为字符串’123’的记录。
    SELECT * FROM products WHERE product_id = ‘123’;
    在这个例子中,我们将字符串’123’与product_id字段进行比较。由于product_id是一个INT类型的字段,而我们使用的是一个字符串,MySQL会自动将字符串’123’转换为INT类型,然后进行比较。
    在上面给出的例子中,将产品ID的字段以字符串形式进行比较是有问题的。主要问题有两个:
  4. 性能问题:使用字符串进行比较会导致MySQL进行字符串到整数的隐式转换,这可能会影响查询的性能。隐式转换需要进行额外的计算和比较操作,而明确指定数据类型可以避免这种开销。
  5. 可读性问题:将一个整数字段与字符串进行比较可能会使代码难以理解和维护。其他人阅读代码时可能会误解意图或不清楚其背后的隐式转换。明确地指定操作数的数据类型可以增加代码的可读性和可维护性。
  6. 不准确的结果:隐式转换可能导致不准确的结果。由于MySQL自动进行转换时可能会截断、舍入或改变数据精度,所以结果可能与预期不符。显式地指定数据类型可以确保准确的比较和计算。
    为了解决这些问题,建议在编写SQL时明确指定操作数的数据类型。在这个例子中,正确的写法是将产品ID的值作为整数进行比较,而不是以字符串形式比较:
SELECT * FROM products WHERE product_id = 123;

通过明确指定数据类型,可以避免性能问题和提高代码可读性,确保查询的准确性和一致性。
3、关联更新、删除

UPDATE operation o
SET    status = 'applying'
WHERE  o.id IN (SELECT idFROM   (SELECT o.id,o.statusFROM   operation oWHERE  o.group = 123AND o.status NOT IN ( 'done' )ORDER  BY o.parent,o.idLIMIT  1) t);

优化为:

UPDATE operation oJOIN  (SELECT o.id,o.statusFROM   operation oWHERE  o.group = 123AND o.status NOT IN ( 'done' )ORDER  BY o.parent,o.idLIMIT  1) tON o.id = t.id
SET    status = 'applying'

其他:
让我们通过例子来说明关联删除和关联更新对SQL性能的影响。

关联删除的性能影响示例

假设我们有两个表:orders(订单表)和 order_items(订单详情表),它们之间通过 order_id 进行关联。现在,我们需要删除具有特定条件的订单以及对应的订单详情。我们可以使用关联删除进行操作:

DELETE o, oi
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.status = 'cancelled';

上述语句使用关联删除的方式,在单个操作中删除了符合条件的订单表和订单详情表中的数据。这样的关联删除可以减少与数据库的多次交互,提高性能。

通过使用关联删除,我们可以一次性删除相关的数据,避免了多次独立删除的开销,从而减少了请求和响应的次数,提高了删除操作的性能。

关联更新的性能影响示例

假设我们有两个表:products(产品表)和 inventory(库存表),它们之间通过 product_id 进行关联。现在,我们需要将产品表中特定条件的产品的库存数量更新为0。我们可以使用关联更新进行操作:

UPDATE products p
JOIN inventory i ON p.product_id = i.product_id
SET p.stock = 0
WHERE i.quantity < 0;

上述语句使用关联更新的方式,在单个操作中更新了产品表和库存表中符合条件的数据。通过关联更新,我们可以一次性更新相关数据,避免了多次独立更新的开销,从而减少了请求和响应的次数,提高了更新操作的性能。

需要注意的是,关联删除和关联更新的性能影响也会受到其他因素的影响,例如表的大小、索引的使用、服务器的配置等。因此,在实际使用中,需要综合考虑并做好性能测试,以获得最佳的性能结果。
4、混合排序

SELECT *
FROM   my_order oINNER JOIN my_appraise a ON a.orderid = o.id
ORDER  BY a.is_reply ASC,a.appraise_time DESC
LIMIT  0, 20

由于 is_reply 只有0和1两种状态,我们按照下面的方法重写后,执行时间从1.58秒降低到2毫秒。
优化为:

SELECT *
FROM   ((SELECT *FROM   my_order oINNER JOIN my_appraise aON a.orderid = o.idAND is_reply = 0ORDER  BY appraise_time DESCLIMIT  0, 20)UNION ALL(SELECT *FROM   my_order oINNER JOIN my_appraise aON a.orderid = o.idAND is_reply = 1ORDER  BY appraise_time DESCLIMIT  0, 20)) t
ORDER  BY  is_reply ASC,appraisetime DESC
LIMIT  20;

其他:
让我们通过一个例子来说明混合排序对性能的影响:

假设我们有一个名为products的表,其中包含大量产品的信息,包括product_name(产品名称)、price(价格)和stock(库存)。现在,我们需要按照价格升序排序,并在价格相同时,按照库存降序排序。

方法一:使用混合排序

SELECT *
FROM products
ORDER BY price ASC, stock DESC;

上述查询使用混合排序,首先按照价格升序排序,如果价格相同,则按照库存降序排序。

方法二:分步排序

SELECT *
FROM (SELECT *FROM productsORDER BY stock DESC
) AS subquery
ORDER BY price ASC;

上述查询使用两个步骤来实现相同的排序需求。首先,我们按照库存降序排序,然后将结果作为子查询。接下来,在子查询的结果上按照价格升序排序。

这里需要注意的是,具体情况可能因数据集的大小和索引等因素而有所不同。以下是对性能影响的一些可能情况:

  • 混合排序性能影响:混合排序在单个查询中同时使用多个排序条件。这样可以避免执行额外的子查询,并减少查询过程中的数据整理。因此,相对而言,混合排序可能在性能方面更有效率。

  • 分步排序性能影响:分步排序通过执行多个查询来实现相同的排序需求。这涉及到执行子查询和在子查询结果上执行额外的排序操作。因此,相对而言,分步排序可能会产生更多的开销,特别是在大型数据集上。

总的来说,混合排序在单个查询中同时使用多个排序条件,可以避免额外的查询和数据整理开销,可能在性能方面更优。然而,具体情况仍需根据数据集的大小、索引设计、查询复杂度等因素进行评估和测试,以确定最佳的排序方法。
5、EXISTS语句

SELECT *
FROM   my_neighbor nLEFT JOIN my_neighbor_apply sraON n.id = sra.neighbor_idAND sra.user_id = 'xxx'
WHERE  n.topic_status < 4AND EXISTS(SELECT 1FROM   message_info mWHERE  n.id = m.neighbor_idAND m.inuser = 'xxx')AND n.topic_type <> 5
优化为:
SELECT *
FROM   my_neighbor nINNER JOIN message_info mON n.id = m.neighbor_idAND m.inuser = 'xxx'LEFT JOIN my_neighbor_apply sraON n.id = sra.neighbor_idAND sra.user_id = 'xxx'
WHERE  n.topic_status < 4AND n.topic_type <> 5

其他:
当使用EXISTS语句时,以下是一些真实世界的例子,可以帮助你理解其性能优化的影响:

  1. 验证关联记录是否存在:假设你有一个订单表和一个订单详情表,你想要检查是否存在至少一个订单有关联的订单详情。你可以使用EXISTS语句来实现:

    SELECT order_id
    FROM orders
    WHERE EXISTS (SELECT * FROM order_details WHERE order_details.order_id = orders.order_id);
    

    通过使用合适的索引和适当的子查询优化,可以帮助加快此查询的执行速度。

  2. 检查未参加活动的客户:假设你有一个客户表和一个活动表,你想要找出所有未参加任何活动的客户。你可以使用EXISTS语句来实现:

    SELECT customer_id, name
    FROM customers
    WHERE NOT EXISTS (SELECT * FROM activities WHERE activities.customer_id = customers.customer_id);
    

    使用合适的索引和适当的子查询优化可以提高查询性能并减少处理时间。

  3. 检查关联表中的重复记录:假设你有一个学生表和一个成绩表,你想要检查是否有学生在成绩表中有重复的记录。你可以使用EXISTS语句来实现:

    SELECT student_id
    FROM students
    WHERE EXISTS (SELECT student_id FROM scores GROUP BY student_id HAVING COUNT(*) > 1);
    

    使用适当的索引和合适的子查询优化可以帮助提高查询性能并减少重复记录的处理。

这些是一些使用EXISTS语句的实际例子,其中的性能优化可以通过索引的创建、正确的子查询编写和查询计划的调整来实现。具体的优化方法会根据你的数据库结构和数据量的不同而有所不同,可以根据实际情况进行调整和优化。
性能优化:
当使用EXISTS语句时,以下是一些优化性能的实际例子:

  1. 创建适当的索引:确保在子查询中的关联字段上创建了适当的索引,这将加速查询的执行。例如,在下面的查询中,对order_details表的order_id字段创建索引将提高查询性能:

    SELECT order_id
    FROM orders
    WHERE EXISTS (SELECT * FROM order_details WHERE order_details.order_id = orders.order_id);
    
  2. 使用合适的连接方式:根据实际情况选择合适的连接方式,如使用INNER JOIN或LEFT JOIN代替EXISTS语句。有时候,将EXISTS子查询转换为连接查询可能会更高效。例如,下面的查询使用INNER JOIN代替了EXISTS子查询:

    SELECT orders.order_id
    FROM orders
    INNER JOIN order_details ON order_details.order_id = orders.order_id;
    

    这种方式可以利用连接操作的性能优势。

  3. 简化和优化子查询:确保子查询是简洁和高效的。避免使用不必要的连接和复杂的表达式。优化子查询的逻辑以减少计算和数据处理。例如,可以使用子查询的查询条件来筛选数据,并仅检查所需的列,而不是检查所有列。

    SELECT customer_id, name
    FROM customers
    WHERE NOT EXISTS (SELECT 1 FROM activities WHERE activities.customer_id = customers.customer_id);
    

    在这个例子中,子查询只使用了SELECT 1而不是SELECT *,因为我们只关心是否存在匹配的记录。

  4. 使用LIMIT限制结果集:如果你只关心是否存在匹配的结果,而不是具体的数据,可以使用LIMIT来限制结果集的大小。在子查询中使用LIMIT 1可以告诉MySQL只返回第一条匹配的结果,这样可以减少不必要的计算和开销。

    SELECT *
    FROM orders
    WHERE EXISTS (SELECT * FROM order_details WHERE order_details.order_id = orders.order_id LIMIT 1);
    

    在这个例子中,我们只需要知道是否存在匹配的记录,因此使用LIMIT 1可以提高查询性能。

相关文章:

  • 只有开源才能拯救AI
  • 《NLP入门到精通》栏目导读
  • 面试算法题之合并系列
  • PostgreSQL 入门教程
  • uniapp公共css
  • 家庭医生上门预约小程序源码系统 源码完全开源可二开 带完整搭建教程
  • Lightroom Classic 2023 v12.4
  • docker基于debian11基础环境安装libreoffice
  • vue3 - swiper插件 实现PC端的 视频滑动功能(仿抖音短视频)
  • 宠物社区系统宠物领养小程序,宠物救助小程序系统多少钱?
  • 【打卡】牛客网:BM48 数据流中的中位数
  • OpenAI调查ChatGPT故障;向量搜索的优势与局限
  • 小程序微信登录授权突然没反应的原因和解决方案
  • 数据结构之双向链表
  • 在以BUF,字节存储区中,存放有n个带符号整数。试编写统计其中负偶数个数(假设≤9)并且显示。
  • 【347天】每日项目总结系列085(2018.01.18)
  • 【5+】跨webview多页面 触发事件(二)
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【刷算法】求1+2+3+...+n
  • gf框架之分页模块(五) - 自定义分页
  • JS+CSS实现数字滚动
  • JS函数式编程 数组部分风格 ES6版
  • js正则,这点儿就够用了
  • Less 日常用法
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Redux 中间件分析
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • Vue--数据传输
  • 工作手记之html2canvas使用概述
  • 基于 Babel 的 npm 包最小化设置
  • 检测对象或数组
  • 面试遇到的一些题
  • 前端学习笔记之观察者模式
  • 如何使用 JavaScript 解析 URL
  • ionic异常记录
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • $NOIp2018$劝退记
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (三)uboot源码分析
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • .Net 6.0 处理跨域的方式
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET构架之我见
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • [ NOI 2001 ] 食物链
  • [AI]文心一言爆火的同时,ChatGPT带来了这么多的开源项目你了解吗
  • [Android]Android P(9) WIFI学习笔记 - 扫描 (1)