如何加快此 mysql 连接查询

How to speed up this mysql join query

我有以下查询需要很长时间(大约 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`;

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

这是 EXPLAIN 的结果:

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

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

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

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

正如 Zerkms 在下面正确指出的那样,您正在对交易 table 执行完整的 table 扫描,因此不需要在那里添加索引。

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

MySQL 很少发现每个 table 使用多个索引是明智的,因此添加所有这些索引对 this 查询没有帮助。稍后,我将提供一个 'composite' 可能有帮助的索引。

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

查询是

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

如果没有 WHERE 子句,它需要扫描一个 table 的全部,然后进入另一个 table。从哪个 table 开始?这可能无关紧要。那么可以做什么呢?还有另一种 可能性 。通过让 'composite' 索引完全匹配 GROUP BY,优化器 可能 使用它来避免 "Using temporary, Using filesort";这会帮助一些.

`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 索引就没有用了。那么问题来了"Why are you JOINing on more than id?"

还有一种可能……不过首先……fuel_cost在哪个table?聚合中其余列的同上 (SUM, ...)。如果它们都在 shift 中,那么可能有另一种方法来编写查询,避免通过 JOIN 进行可怕的扩展,然后通过 GROUP BY 进行崩溃。那才是真正的性能杀手。

(re @zerkms) 由于数据在 table 中的结构方式,获取的 的数量对性能比 。 (我不愿说得更具体,因为 TEXT 会有所作为。)

好吧,我刚刚发现我的问题与索引、查询或数据库结构无关。当我 运行 在我的本地服务器上查询时,它很快而在实时数据库上非常慢。经过一些搜索,我发现增加 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