MySql 查询速度慢 1000 倍,LIMIT 稍高(不偏移)

MySql query 1000x slower with slighty higher LIMIT (not offset)

我有一个包含大约 12Mio 记录的 MySQL 数据库。现在我使用以下查询从该数据库中查询所需的行:

SELECT date_time, price_l0, amount_l0, price_l1, amount_l1, price_l2, amount_l2, price_l3,  /* 34 more columns */
FROM book_states
WHERE date_time > ? and
      date_time < ? and
      bookID = ?
ORDER BY date_time ASC
LIMIT 4350

问题是当我使用约 4340 的 LIMIT 时,此查询大约需要 0.002/0.15 秒 到 运行 .但是,如果我使用 4350 的限制,则需要 3.0/0.15 秒 (!) 到 运行.

如果我 select 更少的列,那么非常快和非常慢的查询之间的阈值会稍微高一些,但即使我 select 只有一列,也需要 3 秒或更多,如果 LIMIT 是超过 5000.

现在我怀疑这是一个 MySQL 设置问题或某种 RAM 限制,但由于我无论如何都不是 MySQL 专家,所以我要求你解释是什么原因造成的这个严重的性能问题。

编辑: 这是 JSON 解释查询的数据,该查询耗时 3 秒

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "282333.60"
    },
    "ordering_operation": {
      "using_filesort": true,
      "table": {
        "table_name": "book_states",
        "access_type": "ref",
        "possible_keys": [
          "index1",
          "index2",
          "index3"
        ],
        "key": "index2",
        "used_key_parts": [
          "bookID"
        ],
        "key_length": "2",
        "ref": [
          "const"
        ],
        "rows_examined_per_scan": 235278,
        "rows_produced_per_join": 81679,
        "filtered": "34.72",
        "index_condition": "(`datastore`.`book_states`.`bookID` <=> 29)",
        "cost_info": {
          "read_cost": "235278.00",
          "eval_cost": "16335.84",
          "prefix_cost": "282333.60",
          "data_read_per_join": "14M"
        },
        "used_columns": [
          "id",
          "date_time",
          "bookID"
        ],
        "attached_condition": "((`datastore`.`book_states`.`date_time` > '2018-09-28T16:18:49') and (`datastore`.`book_states`.`date_time` < '2018-09-29T23:18:49'))"
      }
    }
  }
}

您查询的最佳索引是:(bookID, date_time)。注意列的顺序,这很重要。

MySQL 正在努力使用现有索引优化您的查询。它可以 select 记录,使用您提到的索引的 date_time 部分(或使用 bookId) 上的索引,然后对结果进行排序。

或者,它可以扫描您的复合索引(其中包含按 date/time 排序的记录),过滤掉不需要的书籍。

这两种方法之间的选择就是您(大概)看到的。哪个更好取决于收集的统计数据,它们必然只提供部分信息。

因此,切换索引中的列,问题就会消失,至少对于这个特定的查询。