group by 和 group concat ,不使用main pk优化mysql查询

2024-04-01

我的例子是 MYSQL 版本是 5.6.34-日志

Problem摘要以下查询需要40秒, 订单商品 table

  • has 758423 records

    And PAYMENT table

  • has 177272 records

And 提交条目 table

  • has 2165698 records

    as A Whole表数。

详细信息如下:

  • 我有这个疑问,请参考[1]

  • 我已经添加了SQL_NO_CACHE用于测试重复测试时重新
    query.

  • 我已经优化了索引参考[2],但不显着
    改进。

  • 在这里查找表结构[3]

  • 查找使用的解释计划[4]

[1]

     SELECT SQL_NO_CACHE
          `payment`.`id`                                                                                    AS id,
          `order_item`.`order_id`                                                                           AS order_id,


          GROUP_CONCAT(DISTINCT (CASE WHEN submission_entry.text = '' OR submission_entry.text IS NULL
            THEN ' '
                                 ELSE submission_entry.text END) ORDER BY question.var DESC SEPARATOR 0x1D) AS buyer,


          event.name                                                                                        AS event,
          COUNT(DISTINCT CASE WHEN (`order_item`.status > 0 OR (
            `order_item`.status != -1 AND `order_item`.status >= -2 AND `payment`.payment_type_id != 8 AND
            payment.make_order_free = 1))
            THEN `order_item`.id
                         ELSE NULL END)                                                                     AS qty,
          payment.currency                                                                                  AS `currency`,
          (SELECT SUM(order_item.sub_total)
           FROM order_item
           WHERE payment_id =
                 payment.id)                                                                                AS sub_total,
          CASE WHEN payment.make_order_free = 1
            THEN ROUND(payment.total + COALESCE(refunds_total, 0), 2)
          ELSE ROUND(payment.total, 2) END                                                                  AS 'total',
          `payment_type`.`name`                                                                             AS payment_type,
          payment_status.name                                                                               AS status,
          `payment_status`.`id`                                                                             AS status_id,
          DATE_FORMAT(CONVERT_TZ(order_item.`created`, '+0:00', '-8:00'),
                      '%Y-%m-%d %H:%i')                                                                     AS 'created',
          `user`.`name`                                                                                     AS 'agent',
          event.id                                                                                          AS event_id,
          payment.checked,
          DATE_FORMAT(CONVERT_TZ(payment.checked_date, '+0:00', '-8:00'),
                      '%Y-%m-%d %H:%i')                                                                     AS checked_date,
          DATE_FORMAT(CONVERT_TZ(`payment`.`complete_date`, '+0:00', '-8:00'),
                      '%Y-%m-%d %H:%i')                                                                     AS `complete date`,
          `payment`.`delivery_status`                                                                       AS `delivered`
        FROM `order_item`
          INNER JOIN `payment`
            ON payment.id = `order_item`.`payment_id` AND (payment.status > 0.0 OR payment.status = -3.0)
          LEFT JOIN (SELECT
                       sum(`payment_refund`.total) AS `refunds_total`,
                       payment_refunds.payment_id  AS `payment_id`
                     FROM payment
                       INNER JOIN `payment_refunds` ON payment_refunds.payment_id = payment.id
                       INNER JOIN `payment` AS `payment_refund`
                         ON `payment_refund`.id = `payment_refunds`.payment_id_refund
                     GROUP BY `payment_refunds`.payment_id) AS `refunds` ON `refunds`.payment_id = payment.id
#           INNER JOIN event_date_product ON event_date_product.id = order_item.event_date_product_id
#           INNER JOIN event_date ON event_date.id = event_date_product.event_date_id
          INNER JOIN event ON event.id = order_item.event_id
          INNER JOIN payment_status ON payment_status.id = payment.status
          INNER JOIN payment_type ON payment_type.id = payment.payment_type_id
          LEFT JOIN user ON user.id = payment.completed_by
          LEFT JOIN submission_entry ON submission_entry.form_submission_id = `payment`.`form_submission_id`
          LEFT JOIN question ON question.id = submission_entry.question_id AND question.var IN ('name', 'email')
        WHERE 1 = '1' AND (order_item.status > 0.0 OR order_item.status = -2.0)
        GROUP BY `order_item`.`order_id`
        HAVING 1 = '1'
        ORDER BY `order_item`.`order_id` DESC
        LIMIT 10

[2]

 CREATE INDEX order_id
      ON order_item (order_id);

    CREATE INDEX payment_id
      ON order_item (payment_id);

    CREATE INDEX status
      ON order_item (status);

第二个表

CREATE INDEX payment_type_id
  ON payment (payment_type_id);

CREATE INDEX status
  ON payment (status);

[3]

CREATE TABLE order_item
(
  id                         INT AUTO_INCREMENT
    PRIMARY KEY,
  order_id                   INT                                 NOT NULL,
  form_submission_id         INT                                 NULL,
  status                     DOUBLE DEFAULT '0'                  NULL,
  payment_id                 INT DEFAULT '0'                     NULL
);

第二个表

CREATE TABLE payment
(
  id                 INT AUTO_INCREMENT,
  payment_type_id    INT                                 NOT NULL,
  status             DOUBLE                              NOT NULL,
  form_submission_id INT                                 NOT NULL,
  PRIMARY KEY (id, payment_type_id)
);

[4]运行代码片段以查看表格EXPLAINHTML 格式

<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
<table border="1" style="border-collapse:collapse">
<tr><th>id</th><th>select_type</th><th>table</th><th>type</th><th>possible_keys</th><th>key</th><th>key_len</th><th>ref</th><th>rows</th><th>Extra</th></tr>
<tr><td>1</td><td>PRIMARY</td><td>payment_status</td><td>range</td><td>PRIMARY</td><td>PRIMARY</td><td>8</td><td>NULL</td><td>4</td><td>Using where; Using temporary; Using filesort</td></tr>
<tr><td>1</td><td>PRIMARY</td><td>payment</td><td>ref</td><td>PRIMARY,payment_type_id,status</td><td>status</td><td>8</td><td>exp_live_18092017.payment_status.id</td><td>17357</td><td></td></tr>
<tr><td>1</td><td>PRIMARY</td><td>payment_type</td><td>eq_ref</td><td>PRIMARY</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.payment.payment_type_id</td><td>1</td><td></td></tr>
<tr><td>1</td><td>PRIMARY</td><td>user</td><td>eq_ref</td><td>PRIMARY</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.payment.completed_by</td><td>1</td><td></td></tr>
<tr><td>1</td><td>PRIMARY</td><td>submission_entry</td><td>ref</td><td>form_submission_id,idx_submission_entry_1</td><td>form_submission_id</td><td>4</td><td>exp_live_18092017.payment.form_submission_id</td><td>2</td><td></td></tr>
<tr><td>1</td><td>PRIMARY</td><td>question</td><td>eq_ref</td><td>PRIMARY,var</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.submission_entry.question_id</td><td>1</td><td>Using where</td></tr>
<tr><td>1</td><td>PRIMARY</td><td>order_item</td><td>ref</td><td>status,payment_id</td><td>payment_id</td><td>5</td><td>exp_live_18092017.payment.id</td><td>3</td><td>Using where</td></tr>
<tr><td>1</td><td>PRIMARY</td><td>event</td><td>eq_ref</td><td>PRIMARY</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.order_item.event_id</td><td>1</td><td></td></tr>
<tr><td>1</td><td>PRIMARY</td><td>&lt;derived3&gt;</td><td>ref</td><td>key0</td><td>key0</td><td>5</td><td>exp_live_18092017.payment.id</td><td>10</td><td>Using where</td></tr>
<tr><td>3</td><td>DERIVED</td><td>payment_refunds</td><td>index</td><td>payment_id,payment_id_refund</td><td>payment_id</td><td>4</td><td>NULL</td><td>1110</td><td></td></tr>
<tr><td>3</td><td>DERIVED</td><td>payment</td><td>ref</td><td>PRIMARY</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.payment_refunds.payment_id</td><td>1</td><td>Using index</td></tr>
<tr><td>3</td><td>DERIVED</td><td>payment_refund</td><td>ref</td><td>PRIMARY</td><td>PRIMARY</td><td>4</td><td>exp_live_18092017.payment_refunds.payment_id_refund</td><td>1</td><td></td></tr>
<tr><td>2</td><td>DEPENDENT SUBQUERY</td><td>order_item</td><td>ref</td><td>payment_id</td><td>payment_id</td><td>5</td><td>func</td><td>3</td><td></td></tr></table>
</body>
</html>

预期结果

它必须是 40 秒而不是小于 5

重要的 Updates

1)回复评论1:这两个表上根本没有外键。

更新1: On local the original查询需要40秒如果我删除了only下面就变成了25秒 saves 15秒

GROUP_CONCAT(DISTINCT (CASE WHEN submission_entry.text = '' OR submission_entry.text IS NULL
    THEN ' '
                         ELSE submission_entry.text END) ORDER BY question.var DESC SEPARATOR 0x1D) AS buyer

如果我删除only大约在同一时间40秒 no save!

COUNT(DISTINCT CASE WHEN (`order_item`.status > 0 OR (
    `order_item`.status != -1 AND `order_item`.status >= -2 AND `payment`.payment_type_id != 8 AND
    payment.make_order_free = 1))
    THEN `order_item`.id
                 ELSE NULL END)                                                                     AS qty,

如果我删除only它需要大约36秒 saves 4秒

(SELECT SUM(order_item.sub_total)
   FROM order_item
   WHERE payment_id =
         payment.id)                                                                                AS sub_total,
  CASE WHEN payment.make_order_free = 1
    THEN ROUND(payment.total + COALESCE(refunds_total, 0), 2)
  ELSE ROUND(payment.total, 2) END                                                                  AS 'total',

Remove HAVING 1=1;优化器may不够聪明而忽视它。请提供EXPLAIN SELECT (不在 html 中)来查看优化器正在做什么。

在这种情况下进行复合PK似乎是错误的:PRIMARY KEY (id, payment_type_id)。请证明其合理性。

请解释一下含义status或需要DOUBLE: status DOUBLE

需要花费一些努力才能找出查询如此慢的原因。让我们首先讨论标准化部分,例如日期、事件名称和货币。这就是将查询减少到足以找到所需的行,但不是每行的详细信息。如果还是很慢,我们来调试一下。如果它“快”,则将其他内容一一添加回来,以找出导致性能问题的原因。

Is just id the PRIMARY KEY每张桌子的?或者是否还有更多例外(例如payment)?

指定一个值似乎是“错误的”question.var,但随后使用LEFT暗示它是可选的。请全部更改LEFT JOINs to INNER JOINs除非我在这个问题上弄错了。

是否有任何表(也许submission_entry and event_date_product)“多对多”映射表?如果是这样,请按照提示操作here http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table以获得一些性能提升。

当您回来时请提供SHOW CREATE TABLE对于每张桌子。

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

group by 和 group concat ,不使用main pk优化mysql查询 的相关文章

  • 外键和索引

    我有 2 张桌子 products and 类别 每个类别有很多产品 一个产品可以属于多个类别 products product id int primary auto increment name unique etc 类别 catego
  • 如何使用 SQL 通过表示多级订单的 varchar 字段正确排序?

    我不太喜欢数据库 我发现在查询上出现以下问题SQL服务器数据库旧的遗留应用程序的 我声明不幸的是我无法更改数据库结构 字段类型 这非常难看 我有以下情况 SELECT Sottocategoria IdSottocategoria IdCa
  • SQL UPDATE 语句根据另一个现有行更新列

    基本上我有一个与下表具有相似格式的表格 我想做的是根据这个逻辑更新 Col4 如果 Col2 为空 则用 Col3 更新 Col4 如果 Col2 不为 null 则在 Col1 中查找与 Col2 中的值匹配的值 使用 col3 中的相应
  • 如何在文件系统中存储图像

    目前 我已将图像 最大 6MB 作为 BLOB 存储在 InnoDB 表中 随着数据大小的增长 夜间备份变得越来越慢 阻碍了正常性能 因此 二进制数据需要进入文件系统 指向文件的指针将保存在数据库中 数据具有树状关系 main site u
  • django AuditTrail 与还原

    我正在开发一个新的网络应用程序 我需要将数据库中的任何更改存储到审核表中 此类审计表的目的是 稍后在真正的物理审计中 我们可以确定在某种情况下发生了什么 谁编辑了什么以及数据库当时的状态是什么 复杂的计算 所以大多数审计表将被写入而不是读取
  • 如何将 javax.persistence.Column 定义为 Unsigned TINYINT?

    我正在基于 MySQL 数据库中的现有表创建 Java 持久性实体 Bean 使用 NetBeans IDE 8 0 1 我在这个表中遇到了一个字段 其类型为 无符号 TINYINT 3 我发现可以执行以下操作将列的类型定义为 unsign
  • 在 Mysql 上使用 EntityManager JPA 运行脚本

    我正在尝试运行脚本 sql 文件 但由于我尝试了多种方法 因此出现多个错误 这是我的主要 sql 脚本 INSERT INTO Unity VALUES 11 paq 0 2013 04 15 11 41 37 Admin Paquete
  • 计算 mysql 数据库行数的最佳方法

    在遇到 mysql 查询加载时间慢的问题后 我现在正在寻找计算行数的最佳方法 我曾经愚蠢地使用过mysql num rows 函数来做到这一点 现在意识到这是最糟糕的方法 我实际上正在制作一个分页来用 PHP 制作页面 我找到了几种计算行数
  • MySQL - 选择一行 - 然后相对于所选行的下一个和上一个

    我会尽力澄清这一点 我需要在不使用 id 的情况下选择特定行和该选定行的前一个相对行以及该选定行的下一个相对行 这可能吗 简而言之 上一篇和下一篇 我不能 也许我只是不知道如何 使用 id 的原因是因为它们不是按顺序排列的 正如您从这个相当
  • 如何使用wireshark清晰捕获mysql查询sql

    因为我们使用远程开发Mysql服务器 所以不能轻易检查查询sql 如果使用本地服务器可以tail f general log file查看调用某个http接口时执行了哪些sql 所以我安装了一个wireshark捕获这些从本地发送的查询sq
  • Laravel 5.4 升级 - 违反完整性约束 - 列不能为空

    奇怪的是 所有这些都在 5 2 中工作 但我不知道可以改变什么来实现这一点 下面是错误和正在插入的数组 SQLSTATE 23000 Integrity constraint violation 1048 Column gender can
  • 可以重复应用并产生相同结果的数据库操作吗?

    我现在一片空白 或者像有些人说的那样 正在经历一个高级时刻 我知道这个概念有一个正式的定义和名称 其中在数据库中运行的数据库操作 存储过程 如果重复运行将产生相同的结果 它属于数学家的自反 对称 传递等类型 您的意思是 确定性 吗 如果使用
  • 什么是“数据库实体”以及哪些类型的 DBMS 项目被视为实体? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • MySQL集群启动失败

    这不是我第一次创建ndbcluster 但我没有收到这样的问题 我正在关注本手册 https hub docker com r mysql mysql cluster by mysql团队 我正在使用回显的默认配置在此 GitHub 存储库
  • 从对象定义生成数据库表

    我知道有几种 自动 方法可以创建数据访问层来操作现有数据库 LINQ to SQL Hibernate 等 但我有点厌倦了 我相信应该有更好的做事方式 比如 在 Visio 中创建 更改表 使用 Visio 的 更新数据库 创建 更改数据库
  • PostgreSQL - 致命:用户“myuser”身份验证失败[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我刚刚在我的 Ubuntu Box 中安装了 PostGreSQL 我想做的第一件事就是创建一个数据库 我读了文档 http www postgres
  • 使用来自另一个数据库的选择查询更新 mysql 表

    我有两个数据库 我想用另一个数据库表中的值更新一个表 我正在使用以下查询 但它不起作用 UPDATE database1 table1 SET field2 database2 table1 field2 WHERE database1 t
  • dbms_xmlgen.getxml - 如何设置日期格式

    我们使用 dbms xmlgen getxml 实用程序通过 SQL 查询生成 xml 该查询从几乎 10 15 个相关表中获取数据 默认情况下 日期格式生成于dd MMM yy格式 有什么方法可以在 dbms xmlgen getxml
  • 更改mysql数据库表中的日期格式

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

    我有一个这样的表结构 TABLE NAME counter id datetime url ip 1 2013 04 12 13 27 09 url1 ip01 2 2013 04 13 10 55 43 url2 ip02 3 2013

随机推荐

  • JavaScript 错误:“不是构造函数”

    我使用backbone js以及jquery和underscore js 这是我的一些代码 它还没有做任何事情 奇怪的是 点击 url users 后没有错误 发生错误的唯一一次是当我单击转到不同的哈希 然后单击返回转到 users 时 这
  • 在Python中动态评估简单的布尔逻辑

    我有一些动态生成的布尔逻辑表达式 例如 A 或 B 和 C 或 D A 或 A 和 B A 空 计算结果为 True 占位符被替换为布尔值 我是不是该 将此信息转换为 Python 表达式 例如True or True or False a
  • 如何模拟dbcontext?

    我正在使用实体框架核心 1 0 rc2 这是班级 public class ApplicationDbContext DbContext public ApplicationDbContext DbContextOptions
  • 如何定义两个实体之间的多重关系?

    我有一个场景user可以上传多个photos 一对多 这user还可以有默认照片 一对一 然而 我实体框架core 2 0告诉我当我使用以下代码时他无法识别这种关系 public class User public Guid Id get
  • 如果在嵌套集合上使用 SelectMany,则保留父实例

    我有我的模型的集合Person class Person public string FirstName get set public string LastName get set public string Company get se
  • 搜索 .pst 文件时,FOR 在到达隐藏的快捷方式文件夹时不断循环

    以下命令创建一个无限循环 这不是我想要的 因为我正在迭代文件并且它需要在某个时候结束 这是我所拥有的 cd C FOR R i IN pst do echo i 看看会发生什么 当它到达 AppData 并找到 pst 在 AppData
  • 如何在 Flutter 中构建静态 datePicker 小部件,而不需要先按按钮

    我想用 Flutter 构建一个静态 DatePicker 而不需要之前按下按钮 当屏幕加载时 它应该显示选择器 尝试了 flutter cupertino date picker 尝试了 flutter datetime picker 1
  • 比较 D3.js 中的两个时间对象

    在 D3 js 中 我目前正在尝试根据数据数组是否包含该时间来填充一个空数组 数组仅包含每 5 分钟后的时间戳 如果数据数组包含时间 则应复制该值 否则为 null 但是当我尝试比较两个时间对象时它无法正常工作 以下是代码 当前代码不是复制
  • Android 在来电时关闭媒体服务

    我对 android 和 java 真的很陌生 我正在制作一个应用程序 它有一个媒体服务 我希望媒体在来电时停止或暂停 这是我的媒体服务代码 公共类 ServiceMusic 扩展服务 MediaPlayer music Override
  • “Mac 开发者”和“第三方 Mac 开发者应用程序”之间的区别

    有什么区别Mac Developer and 3rd Party Mac Developer Application配置文件在Code Signing Identity 哪一个适用于 Mac App Store 分发 我也为此摸不着头脑有一
  • CURLOPT_FOLLOWLOCATION 无法激活[重复]

    这个问题在这里已经有答案了 所以我在多个服务器上不断收到这个恼人的错误 它是一个警告 所以我会忽略它 但我需要该功能 警告 curl setopt function curl setopt 当启用 safe mode 或在第 56 行 ho
  • 为android中的应用程序制作小部件

    我已经在android中做了一个应用程序 现在我的要求是我想为此应用程序制作一个小部件 我已经做了一个Widget Demo 但我不知道如何通过小部件图标启动我的应用程序 请给我一个方法来做到这一点 任何帮助将不胜感激 主要类别 publi
  • 将 CLR 类型转换为 void* 并返回

    例如 如何正确转换 CLR 类型Foo to void 过一段时间再回来 场景是 我在 DLL 中有一些非托管代码 可以总结为 class Handler void obj void call void obj int detail voi
  • 使用 JavaScript 获取给定月份的给定工作日

    我试图获取某个日期所在月份的第 n 个工作日 例如 第二个星期日 例如 如果日期是 2015 年 8 月 24 日 我想这样做 nthDayOfMonth 0 2 new Date 2015 7 24 并获取 2015 年 8 月 9 日
  • iPhone REST 客户端 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • AlertDialog 中的 Android EditText 似乎太宽

    下图中的 EditText 似乎太宽了 我假设我以某种方式滥用了 SDK 除非确信 否则我不会寻找一种方法来指定边缘 填充像素的数量EditText 这个看起来比较合适 这是我的代码 创建第一个 创建标签 对话框 final Dao
  • websphere - CWWKE0054E 错误无法打开文件

    我正在尝试从命令行运行 websphere liberty profile 服务器 我正在按照此处所述的步骤进行操作 https developer ibm com wasdev downloads liberty profile usin
  • netstandard20 中的 System.Data.Linq

    我有一个引用 Net 4 6 项目的 netstandard20 项目 除了我调用 Net 4 6 项目中的任何功能之外 所有项目都会编译和运行 我收到以下错误 FileNotFoundException 无法加载文件或程序集 System
  • 自动运行 CSS 更改

    我知道有解决方案可以解决这个问题 但我想在我的 自己的 你必须知道你的限制 Hello stackoverflow 路径上完成这项工作 所以我想要一种轮播 只要用户不将鼠标悬停在 ul 区域上 整个 ul 元素就会在每个设定的时间间隔内获得
  • group by 和 group concat ,不使用main pk优化mysql查询

    我的例子是 MYSQL 版本是 5 6 34 日志 Problem摘要以下查询需要40秒 订单商品 table has 758423 records And PAYMENT table has 177272 records And 提交条目