如何加快这个mysql连接查询

时间:2016-09-05 05:06:13

标签: mysql indexing query-optimization explain

我有以下查询需要很长时间(约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.然而,我仍然需要更快的速度(可能通过添加更多索引或更改它们?)。

这是EXPLAIN的结果: enter image description here

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

enter image description here

3 个答案:

答案 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

What to set innoDB buffer pool and why

MySQL Reference Manual: Configuring innoDB buffer pool size