如何加快此 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
我有以下查询需要很长时间(大约 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