【问题标题】:How to speed up this mysql join query如何加快这个mysql连接查询
【发布时间】:2017-01-12 10:46:00
【问题描述】:

我有以下查询需要很长时间(大约 1 分钟):

SELECT `transaction`.`fuel_terminal_id`, `transaction`.`xboard_id`, `transaction`.`gas_station_id`, `transaction`.`operator_id`, `transaction`.`shift_id`, `transaction`.`fuel_type`, `transaction`.`purchase_type`, `shift`.`num` AS `shiftNum`, `shift`.`shift_state_id` AS `shiftStateId`, `shift`.`start_totalizer_dispenser_1` AS `startTotalizerDispenser1`, `shift`.`start_totalizer_dispenser_2` AS `startTotalizerDispenser2`, `shift`.`end_totalizer_dispenser_1` AS `endTotalizerDispenser1`, `shift`.`end_totalizer_dispenser_2` AS `endTotalizerDispenser2`, min(shift.start_time)AS shiftStartTime, max(shift.end_time)AS shiftEndTime, count(*)AS groupCount, sum(fuel_cost)AS sumFuelCost, sum(payment_cost)AS sumPaymentCost, sum(actual_amount / 100)AS sumActualAmount, min(start_fuel_time)AS firstFuelingDate,max(end_fuel_time)AS lastFuelingDate 
FROM `transaction` 
LEFT JOIN `shift` 
ON shift.gs_id = TRANSACTION .gas_station_id 
AND shift.terminal_id = TRANSACTION .fuel_terminal_id 
AND shift.id = TRANSACTION .shift_id 
AND shift.start_time = TRANSACTION .shift_start_time
GROUP BY `transaction`.`gas_station_id`, 
`transaction`.`fuel_terminal_id`, 
`transaction`.`shift_start_time`, 
`transaction`.`fuel_type`, 
`transaction`.`purchase_type`,  
`transaction`.`operator_id`;

我可以通过将“shift”表中“operator_id”列的数据大小从 VARCHAR 255 更改为 VARCHAR 16 并更改“事务”表中该列的数据类型来加快查询速度(大约 25%)从 TEXT 到 VARCHAR 16。但是,我仍然需要加快速度(也许通过添加更多索引或更改它们?)。

这是 EXPLAIN 的结果:

我在MySQL 5.7 Reference Manual 中读到,如果“possible_keys”列为 NULL,则没有相关索引。所以,我想知道是否有人可以帮助我了解我是否没有选择正确的索引?这些是我放在表“事务”上的索引:

【问题讨论】:

  • 您从transaction 表中选择所有内容。当您从表中选择所有内容时 - 不需要索引。
  • @zerkms:我从transaction 表中只选择了 7 列(总共有 26 列)
  • 您已选择所有行。
  • @zerkms:抱歉,我不明白你的意思。我从 EXPLAIN 结果中了解到,表事务已被完全扫描。同样来自 MySQL 参考手册,由于可能的键列是 NULL,我想也许我应该在这个表上添加更多索引。我误解了吗?或者您知道如何加快查询速度吗?
  • 它被完全扫描,因为您选择了所有行。把HDD换成SSD,是io问题(科学猜测)

标签: mysql indexing query-optimization explain


【解决方案1】:

MySQL 很少发现每个表使用多个索引是明智的,因此添加所有这些索引对查询没有帮助。稍后,我将介绍一个可能会有所帮助的“复合”索引。

请为每张桌子提供SHOW CREATE TABLE;我们不得不猜测太多的事情。这可能有助于我们解决您关于TEXT 等的问题。

查询是

上的变体
SELECT a.stuff, b.stuff
    FROM a
    JOIN b ON ...
    -- no WHERE clause
    GROUP BY a...

如果没有WHERE 子句,它需要扫描一张表的所有内容,并到达另一张表。从哪个表开始?可能没关系。那么可以做些什么呢?还有另一种可能性。通过拥有一个完全匹配GROUP BY 的“复合”索引,优化器可能使用它来避免“使用临时,使用文件排序”;这将有助于一些

`transaction`: INDEX(`gas_station_id`, `fuel_terminal_id`, `shift_start_time`,
                     `fuel_type`, `purchase_type`,  `operator_id`)
               -- in that order
 shift: INDEX(gs_id, shift.terminal_id, id, start_time) 
               -- in any order

但是,如果shift 已经有PRIMARY KEY(id),那么新的shift 索引就没有用了。然后是“为什么你JOINingid 更多?”的问题

还有另一种可能...但首先...fuel_cost 在哪个表中?聚合中的其余列也是如此 (SUM, ...)。如果它们都在shift 中,那么可能还有另一种编写查询的方法,通过JOIN 避免可怕的扩展,然后通过GROUP BY 折叠。这才是真正的性能杀手。

(re @zerkms) 由于数据在表中的结构方式,获取的行数列数 对性能更重要。 (我不愿更具体,因为TEXT 可以有所作为。)

【讨论】:

  • 感谢 Rick 提供的有用提示。我刚刚发现我的问题与索引或查询无关,但它是缓冲池的小尺寸。所以我只是将 innodb_buffer_pool_size 从 8M(默认)增加到 2G,现在它工作正常:)
【解决方案2】:

在您的示例中,我在 shift 表中看不到 operator_id 列,所以我不明白更改数据类型如何提高查询性能...

已经说过索引所有正在连接的列应该是最好的索引策略,例如应为以下字段创建索引:

shift.gs_id
shift.terminal_id  
shift.id  
shift.start_time 

正如 Zerkms 在下面正确指出的那样,您正在对事务表执行全表扫描,因此无需在此处添加索引。

但是 MySQL 不会在数据类型不同的连接上使用索引,例如您不能将具有 VARCHAR(32) 数据类型的字段与具有 INT 数据类型的字段连接起来并期望使用索引,因此您应该在连接的两侧使它们相同。如果它们不相同,或者不能更改为相同,那么您的设计就有问题。

【讨论】:

  • 感谢您的回答。除了transaction.shift_id,我已经对您建议的所有字段都有索引。我也添加了这个,但没有改变任何东西:|
  • 连接列两边的数据类型是否一致? - 你能发布索引的 DDL(包括主键)
  • 此查询的单独索引不会改变任何内容。 “例如,以下字段都应该被索引”——这是一个有害的建议。它的依据是什么?
  • @Scoindy:是的,我也检查过它们。它们的类型和大小相同。
  • 我不确定您所说的“单独索引”是什么意思。此外,如果像这样的 cmets 伴随着某种理性或推理,if 将是最有帮助的。
【解决方案3】:

好吧,我刚刚发现我的问题与索引或查询或数据库结构无关。当我在本地服务器上运行查询时,它很快,而在实时数据库上却非常慢。经过一番搜索,我发现增加 buffer_pool_size (比你的数据库大小大一点,在我的例子中,我将它从默认值(8M)增加到 2G)提高了 innoDB 的性能。

阅读以下链接帮助我了解了 innoDb 中的缓冲池以及如何配置它:

MySQL Reference Manual: the innoDB buffer pool

Choosing innoDB buffer pool size

What to set innoDB buffer pool and why

MySQL Reference Manual: Configuring innoDB buffer pool size

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 2014-05-06
    • 2014-07-27
    • 1970-01-01
    • 2015-03-18
    相关资源
    最近更新 更多