我有以下查询需要很长时间(约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%),并且还可以在表“transaction”中更改此列的数据类型从TEXT到VARCHAR 16.然而,我仍然需要更快的速度(可能通过添加更多索引或更改它们?)。
我在MySQL 5.7 Reference Manual中读到如果列“possible_keys”为NULL,则没有相关索引。所以,我想知道是否有人可以帮我理解我是否没有选择正确的索引?这些是我在“交易”表上放置的索引:
答案 0 :(得分:2)
MySQL很少发现每个表使用多个索引是谨慎的,因此添加所有这些索引并没有帮助此查询。片刻之后,我将展示一个“复合材料”。索引可能有所帮助。
请为每张表提供SHOW CREATE TABLE
;我们不得不猜测太多东西。这可能有助于我们解决有关TEXT
等问题的问题
查询是
的变体SELECT a.stuff, b.stuff
FROM a
JOIN b ON ...
-- no WHERE clause
GROUP BY a...
如果没有WHERE
子句,则需要扫描所有一个表,并进入另一个表。从哪个表开始?这可能没关系。那可以做些什么呢?还有一个可能性。通过复合'索引完全匹配GROUP BY
,优化程序可能使用它来避免使用临时,使用filesort&#34 ;;这将有助于一些。
`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
索引无效。接下来是问题"为什么JOINing
超过id
?"
还有另一种可能性......但首先......哪个表格是fuel_cost
?同上聚合中的其余列(SUM
,...)。如果它们都在shift
中,则可能有另一种方法来编写查询,以避免通过JOIN
进行可怕的扩展,然后通过GROUP BY
进行折叠。这是真正的性能杀手。
(re @zerkms)由于数据在表中的结构方式,获取的行的数量对于性能而言比列的数量更重要。 (我更加具体,因为TEXT
可以有所作为。)
答案 1 :(得分:1)
我在示例中的shift表中看不到operator_id列,所以我不明白更改数据类型如何可以提高查询的性能......
已经说过索引所有正在连接的列应该是最好的索引策略,例如应为以下字段创建索引:
shift.gs_id
shift.terminal_id
shift.id
shift.start_time
正如Zerkms在下面正确指出的那样,您正在事务表上执行全表扫描,因此不需要在那里添加索引。
但是MySQL不会在数据类型不相同的连接上使用索引,例如您不能将具有VARCHAR(32)数据类型的字段与具有INT数据类型的字段连接并期望使用索引,因此您应该在连接的两端使它们相同。如果它们不相同,或者不能改变为相同,那么你的设计就会有些可疑。
答案 2 :(得分:0)
好吧,我刚刚发现我的案例中的问题与索引或查询或数据库结构无关。当我在本地服务器上运行查询时,它的速度非常快,而实时数据库则非常慢。经过一些搜索,我发现增加buffer_pool_size(比你的数据库大小稍大,在我的情况下,我从defult值(8M)增加到2G)提高了innoDB的性能。
阅读以下链接有助于我了解innoDb中的缓冲池以及如何配置它:
MySQL Reference Manual: the innoDB buffer pool
Choosing innoDB buffer pool size