通过 Join-Where-Group 通过选择查询正确建立索引,避免使用临时;使用文件排序

2024-06-08

我已经搜索了很多关于下面描述的案例的解决方案,但不幸的是我没有找到类似的案例。

我有以下场景: (作为新用户,该网站拒绝了我的图片,但我可以通过邮件发送它。下面是它的文本表示)

Table 1 "swap_plan"          Table 2 "cell"
ClusterName | SiteID         SiteID    | Cell      |  Time       | Counter
-----------------------      ---------------------------------------------
Cluster A   | SiteID A1      SiteID A1 | Cell A1-1 | day1        | 5
Cluster A   | SiteID A2      SiteID A1 | Cell A1-1 | day2        | 3
Cluster A   | SiteID A3      SiteID A1 | Cell A1-1 | day3        | 6
Cluster A   | SiteID A4      SiteID A1 | Cell A1-2 | day1        | 6
Cluster A   | SiteID A5      SiteID A1 | Cell A1-2 | day2        | 2
Cluster A   | SiteID A6      SiteID A1 | Cell A1-2 | day3        | 9
.......................      ..............................................
Cluster B   | .........      ..............................................

(Where No 1)      (ON Clause "SiteID")            (Where No 2)    Sum(Counter)

我必须显示一些性能指标(表 2“单元”中的“计数器”)、随时间(表 2“单元”中的“时间”)和集群(表 1“swap_plan”中的“ClusterName”)聚合的性能指标。

连接是通过两个表“SiteID”的公共列完成的。请注意,表 2“单元”中的每个 SiteID 由 3 个不同的对象(“单元”)组成。所以,实际上我为每个单元格执行“计数器”的 SUM() 。

查询如下:

SELECT ClusterName,Time,SUM(counter)
FROM cell
INNER JOIN swap_plan ON swap_plan.Siteid = cell.Siteid
WHERE ClusterName='Cluster A' AND Time>=day1 AND Time<=day2
GROUP BY Time

列类型如下:

表1“互换计划”:

  1. 集群名称 - CHAR(30)
  2. 站点 ID - VARCHAR(10)

表2“细胞”:

  1. 站点 ID - VARCHAR(10)
  2. 时间 - 日期时间
  3. 计数器 - INT

“解释”显示如下:

table          type    key           key_len      ref               rows  Extra

swap_plan      ref     Index 1       30           const             31    Using where; Using index; Using temporary; Using filesort
cell           ref     Index_siteid  13           swap_plan.SiteID  368   Using where

使用的索引如下:

swap_plan:索引 1(1.ClusterName 和 2.SiteID)

单元格:Index_siteid(站点ID)

优化器看起来的行数相当低,这很好:

swap_plan:6066 个中的 31 个,cell:660 万个中的 368 个。

我的问题是“使用临时;使用文件排序”。据我了解,这是来自 Group By 所需的排序(如果我删除它,这些过程将不会根据Explain执行)。我发现为了避免它们,您需要在分组依据的列上有一个索引。我有一个特殊的索引,仅包括“时间”列,但这个索引没有被使用,即使有提示“USE INDEX FOR GROUP BY ()”。

因此,我的查询运行速度不够快 - 大约需要 15 秒(假设有 15 个 SiteID 和 10 个日期),我需要将此持续时间缩短到至少一半。

我的主要问题是:

  • 完全可以删除“使用临时;使用文件排序”或 减少执行所需的时间? (我尝试增加 读取缓冲区大小为 16MB,无影响)
  • 在 JOIN 情况下,当在 WHERE 子句中按不同表中的 2 列进行过滤时,在 ON 子句中按第三列进行过滤时,我需要什么样的索引定义
  • 我可以应用哪种 Group By 优化(索引等)?

预先非常感谢您!


我会这样写查询:

SELECT c.time
     , SUM(c.counter)
     , MAX(p.clustername) AS clustername
  FROM cell c

  JOIN swap_plan p
    ON p.siteid      = c.siteid
   AND p.clustername = 'Cluster A'

 WHERE c.time  >=  'day1'
   AND c.time  <=  'day2'
 GROUP
    BY c.time

我肯定有一个索引cell with time作为主导柱。

MySQL 可以使用相同的索引来满足范围谓词(在 WHERE 子句中),并且无需“使用文件排序”操作即可满足 GROUP BY。

... ON cell (time)

根据列的大小,覆盖索引可能会提供最佳性能。覆盖索引包括查询中引用的表中的所有列,因此可以完全从索引页满足查询,而无需查找基础表中的页。

... ON cell (time, siteid, counter)

对于索引swap_plan,我有一个索引site_id作为主导柱,并包括clustername列,其中之一:

... ON swap_plan (clustername, site_id)

or

... ON swap_plan (site_id, clustername)

看起来这两列的组合可能会有一个唯一的约束,即site_id对于给定的情况将是不同的clustername。 (如果不是这样的话,同样(site_id,clustername)元组出现多次,有可能总计counter被充气。

我正在寻找EXPLAIN输出显示“ref”查找swap_plan表中的值c.siteid以及 clustername 的 const(字面值“Cluster A”)值。


对于大小为 31 行和 368 行的表,我们不会看到最佳执行计划和糟糕的执行计划之间的性能(经过的时间)存在显着差异。

当任一表扩展到数百万行时,差异就会变得明显。优化器对执行计划的选择受到每个表的统计信息(大小、行数、列基数)的影响,因此执行计划可能会随着表大小的增加而改变。

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

通过 Join-Where-Group 通过选择查询正确建立索引,避免使用临时;使用文件排序 的相关文章

  • 将 Wamp 服务器升级到 MySQL 8.0.15

    因此 我最近在几个月前安装了 WampServer 并预装了 mySQL 5 7 但我想利用 mySQL 8 附带的 NoSQL 功能 为了更新它 我下载了最新的MySQL版本 将文件夹解压到wamp64的bin目录中 然后 我从 5 7
  • 如何避免此 PDO 异常:当其他未缓冲的查询处于活动状态时无法执行查询

    我想在我的页面中打印一个包含 3 列的简单表格 building name tags and architecture style 如果我尝试检索列表building names and arch styles没有问题 SELECT bui
  • Spark:连接两个相同分区的数据帧时防止洗牌/交换

    我有两个数据框df1 and df2我想在一个名为的高基数字段上多次加入这些表visitor id 我只想执行一次初始洗牌 并让所有连接发生 而无需在 Spark 执行器之间洗牌 交换数据 为此 我创建了另一个名为visitor parti
  • 如何从准备好的语句中获取标量结果?

    是否可以将准备好的语句的结果设置为变量 我正在尝试创建以下存储过程 但失败了 第 31 行出现错误 1064 42000 您的 SQL 语法有错误 检查与您的 MySQL 服务器版本相对应的手册 了解在 stmt USING m c a 附
  • Mysql 中的 MD5 和 Salt

    如何 解密 各种电商存储的密码添加 盐 我不是密码专家 所以 在过去 我使用过类似的东西 SELECT FROM mytable WHERE email email AND passwd MD5 pwd MySql MD5 函数只接受一个参
  • MYSQL:如何从姓氏中找到player_id?

    我现在尝试使用非标准化 摘要 表中的数据填充 testMatch 表 如下 测试匹配表 Field Type Null Key Default Extra match id int 11 NO PRI NULL match date dat
  • 从mysql数据库读取pdf文件

    我正在使用这个例子http www php mysql tutorial com wikis mysql tutorials uploading files to mysql database aspx http www php mysql
  • GROUP_CONCAT 逗号分隔符 - MySQL

    我有一个疑问 我在哪里使用GROUP CONCAT和自定义分隔符 因为我的结果可能包含逗号 这一切都运行良好 但它仍然以逗号分隔 所以我的输出是 Result A Result B Result C 我怎样才能做到这一点 输出是 Resul
  • 我是否应该标准化我的数据库?

    在设计数据库 例如 MySQL 的模式时 会出现是否完全规范化表的问题 一方面 连接 以及外键约束等 非常慢 另一方面 您会获得冗余数据和潜在的不一致 最后优化 是正确的方法吗 即创建一个按书本规范化的数据库 然后查看可以对哪些内容进行非规
  • 我不小心锁定了 MySQL 的 root

    我在 OS X 上使用 MySQL 并使用删除了所有 root 用户DROP USER 然后我又添加了其中一些并做了GRANT ALL on to root localhost 然后在验证确实是的之后注销 我可以登录并执行一些特权操作 不幸
  • 重新排列mysql中的主键

    从MySQL表中删除一些行后如何重新排列主键列值 例如 一个包含 4 行数据的表 主键值为 1 2 3 4 当删除第2行和第3行时 第4行的键值变为2 请帮助我找到解决方案 为什么要这样做 你不需要重新排列您的密钥 因为它只是记录的数字和标
  • MySQL 命令输出在命令行客户端中太宽[重复]

    这个问题在这里已经有答案了 我在用mysql终端模拟器中的命令行客户端lxterminal在Ubuntu中 当我运行以下命令时 mysql gt select from routines where routine name simplep
  • 如何使用Conda安装MySQLdb?

    我已经阅读了有关如何安装 MySQLdb 的几种不同的解释 但我不确定哪种情况适用于我 因为我的错误消息不同 我的系统似乎找不到 MySQLdb 我安装了 pymysql 但我需要导入 MySQLdb 才能使用该库中的过程 感谢您的帮助 c
  • MySQL 多个 IN 条件对同一个表进行子查询

    我有多个带有子查询的 IN 条件 SELECT S name S email FROM something S WHERE 1 NOT IN SELECT id FROM tags WHERE somethingId S id AND 2
  • mysql变量赋值:如何强制赋值顺序?

    由于mysql是一种声明性语言 我找不到强制赋值变量顺序的方法 采取这个查询 SET v1 0 SET v2 0 SELECT v1 v2 FROM MyTable table WHERE v1 v2 is not null AND v2
  • 使用 JOIN 和 UNION 合并不同表中的记录

    我需要创建一个查询来组合两个表中的数据 我认为可能是 JOIN 和 UNION 的组合 在此示例中 我需要列出状态处于活动状态的所有姓名 仅一次 并将他们的葡萄酒 苏打水 晚餐 甜点和水果偏好组合起来 按姓名排序 我不确定单独的 JOIN
  • 如何将 MySql 表导出/转储到文本文件中,包括字段名称(也称为标题或列名称)

    在 MySql 的解释器中 很容易将表及其字段名称转储到屏幕上 似乎没有简单的方法可以将表导出到制表符分隔或 CSV 输出文件包括它的列标题 我尝试仅使用 SQL 或 Linux 命令行来完成此操作 而不用其他语言编写程序 谢谢 将查询通过
  • 为什么运行 docker 容器后 mysql 数据所有权更改为 systemd-journal-remote

    我的mysql数据库存储在 home mysql代替 var lib mysql 该目录曾经属于mysql 但是 当我运行命令时docker compose up使用这个 yml 文件 version 3 services mariadb
  • PHP 中的嵌套 JSON 输出

    我正在为 iOS 应用程序构建 API 并尝试将 mySQL 数据转换为 JSON 字符串进行处理 所需的输出将需要顶级订单详细信息 例如客户名称和地址 然后是订购的产品子数组 我需要的两个表中有相当多的字段 我希望拥有所有字段 我已经构建
  • 我的数据库有错误

    创建表时如下 create table Ticket ticket id integer not null primary key AirlineName varchar not null CustomerName varchar from

随机推荐