我有一个大约有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
问题是,当我使用 LIMIT大约4340 时,此查询需要大约 0.002 / 0.15秒才能运行。但是,如果我使用的限制为 4350 ,则需要 3.0 / 0.15秒(!)才能运行。
如果我选择的列较少,则在非常快和非常慢的查询之间的阈值会略高,但是即使LIMIT大于5000,即使我仅选择一列,也要花费3秒或更长时间。
现在,我怀疑这是MySQL设置问题或某种形式的RAM限制,但是由于我无论如何都不是MySQL专家,所以我想请您解释一下导致此严重性能问题的原因。
编辑: 这是耗时3秒的JSON Explain数据
{
"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'))"
}
}
}
}
答案 0 :(得分:4)
您查询的最佳索引为:(bookID, date_time)
。请注意列的顺序,这很重要。
MySQL正在努力优化现有索引的查询。它可以使用您提到的索引的date_time
部分(或使用bookId)
上的索引来选择记录,然后对结果进行排序。
或者,它可以扫描您的复合索引(按日期/时间排序的记录),从而过滤掉不需要的书籍。
在这两种方法之间进行选择(大概)。哪个更好取决于所收集的统计信息,并且它们必然仅提供部分信息。
因此,切换索引中的列,至少对于此特定查询而言,问题应该消失了。