在大型表上使用LIKE操作时,MySQL查询速度慢

时间:2014-10-21 17:37:01

标签: mysql sql performance indexing

我有一个相当大的表(~6 GB),我在这个查询上遇到了性能问题:

          SELECT f.*,
          TIME_FORMAT(f.scheme, '%H:%i') as scheme,
          TIME_FORMAT(f.actual, '%H:%i') as actual,
          DATE_FORMAT(f.flight_date, '%d-%m-%Y') as flight_date_formatted,
          a.iata
          FROM flights_database f
          LEFT JOIN airports a ON f.airport = a.airportNameClean
          WHERE f.flight_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY)
          AND DATE_ADD(CURDATE(), INTERVAL 2 DAY)
          AND (f.flight_number LIKE 'New York%' OR f.airport LIKE 'New York%' OR f.airline LIKE 'New York%')
          ORDER by f.flight_date DESC, f.flight_scheme DESC
          LIMIT 50"

我已使用EXPLAIN并确定了这些潜在问题

  • 使用多个LIKE&OR让它使用一个范围(使用WHERE)记录并且似乎使其变慢
  • f.flight_scheme DESC,当添加文件时使用。删除后,不使用filesort。

我在flight_date, flight_number, airport, airline, scheme上有一个索引,并报告使用它。 但是这个查询仍然需要大约30秒,这当然太多了。

使用某种子查询来替换OR部分可能会有所帮助。但是,如何确定在运行子查询后我实际需要搜索的搜索查询类型(例如哪一列)。

赞赏的想法和提示。

1 个答案:

答案 0 :(得分:1)

我认为您当前的索引不是查询的最佳选择,主要是因为'或'表达式。你应该创建3个索引。

(flight_number,flight_date,schema)

(机场,flight_date,架构)

(航空公司,flight_date,架构)

然后更改查询以使用三个索引。您也可以稍微玩一下,也可以通过添加订单来修剪每个子查询,并限制为50。

select flight.*,
    TIME_FORMAT(flight.scheme, '%H:%i') as scheme,
    TIME_FORMAT(flight.actual, '%H:%i') as actual,
    DATE_FORMAT(flight.flight_date, '%d-%m-%Y') as flight_date_formatted,
    a.iata
from (
    select *
    from (
        select f.Id,
            f.flight_date,
            f.schema
        from flights_database f
        where f.flight_date between DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                and DATE_ADD(CURDATE(), INTERVAL 2 DAY)
            and f.flight_number like 'New York%'
        order by f.flight_date desc,
            f.schema desc limit 50

        union

        select f.Id,
            f.flight_date,
            f.schema
        from flights_database f
        where f.flight_date between DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                and DATE_ADD(CURDATE(), INTERVAL 2 DAY)
            and f.airline like 'New York%'
        order by f.flight_date desc,
            f.schema desc limit 50

        union

        select f.Id,
            f.flight_date,
            f.schema
        from flights_database f
        where f.flight_date between DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                and DATE_ADD(CURDATE(), INTERVAL 2 DAY)
            and f.airport like 'New York%'
        order by f.flight_date desc,
            f.schema desc limit 50
        ) f1
    order by f1.flight_date desc,
        f.schema desc limit 50
    ) f2
inner join flights_database flight on f2.Id = flight.Id
left join airports a on flight.airport = a.airportNameClean;

目前您的或声明将扩展为: [flight_date,flight_number],[flight_date,航空公司],[flight_date,airport]

因此,当优化器查看您的索引时,它将匹配 [flight_date,flight_number]到你当前的索引[flight_date,flight_number,机场,航空公司,方案](请注意他们如何开始相同),但是当遇到[flight_date,airline]时,没有与此表达式匹配的索引。因此优化器将确定它需要进行索引扫描或表扫描。然后它会再次遇到[flight_date,airport]它会确定这需要索引扫描或表扫描。

使用三个新索引和新查询,它会将三个索引与三个条件匹配,并确定每个索引都需要索引搜索(希望如此)。然后我们包括'scheme'来保存符合条件的所有行的id的行查找。