3

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

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

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”中的“集群名称”)。

连接是通过两个表“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 (SiteID)

优化器看起来的行数非常低,这很好:

交换计划:6066 中的 31 和单元:660 万中的 368。

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

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

我的主要问题是:

  • 是否有可能删除“使用临时;使用文件排序”或减少执行所需的时间?(我尝试将 Read Buffer Size 增加到 16MB,没有效果)
  • 在 JOIN 情况下我需要什么样的索引定义,当在 WHERE 子句中我按不同表中的 2 列过滤时,在 ON 子句中我按第 3 列过滤
  • 我可以应用什么样的 Group By 优化(索引等)?

非常感谢您!

4

1 回答 1

0

我会这样写查询:

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作为time前导列。

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

... ON cell (time)

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

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

对于 上的索引swap_plan,我将有一个索引site_id作为前导列,并包括该clustername列,其中之一是:

... ON swap_plan (clustername, site_id)

或者

... ON swap_plan (site_id, clustername)

看起来这两个列的组合可能会有一个 UNIQUE 约束,即 的值site_id对于给定的 将是不同的clustername。(如果不是这种情况,并且同一个(site_id,clustername)元组多次出现,那么总的总数可能counter会被夸大。

我正在寻找输出以显示从clustername 的值和 const(字面“Cluster A”)值到表EXPLAIN的“ref”查找。swap_planc.siteid


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

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

于 2019-11-26T17:39:01.127 回答