Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql ORBERBY子句使查询速度变慢,尽管结果集很小_Mysql_Sql_Performance_Query Optimization - Fatal编程技术网

Mysql ORBERBY子句使查询速度变慢,尽管结果集很小

Mysql ORBERBY子句使查询速度变慢,尽管结果集很小,mysql,sql,performance,query-optimization,Mysql,Sql,Performance,Query Optimization,我有以下表格(删除不相关的内容): Booking包含约456k行,Payment包含约331k行。以下查询采用0.06秒并返回97行: select * from Booking b join Payment p on b.paymentId = p.id where p.status = 3 如果我添加一个order by子句,则查询将花费4.4s的时间,几乎慢了100倍: select * from Booking b join Payment p on b.paymentId = p.

我有以下表格(删除不相关的内容):

Booking
包含约456k行,
Payment
包含约331k行。以下查询采用0.06秒并返回97行:

select * from Booking b
join Payment p on b.paymentId = p.id
where p.status = 3
如果我添加一个
order by
子句,则查询将花费4.4s的时间,几乎慢了100倍:

select * from Booking b
join Payment p on b.paymentId = p.id
where p.status = 3
order by b.nrOfPassengers
解释第一个查询:

id, select_type, table, type, possible_keys, key,       key_len, ref,  rows,   Extra
1,  SIMPLE,      p,     ALL,  PRIMARY,       NULL,      NULL,    NULL, 331299, Using where
1,  SIMPLE,      b,     ref,  paymentFK,     paymentFK, 9,       p.id, 1,      Using where
第二点:

id, select_type, table, type, possible_keys, key,       key_len, ref,  rows,   Extra
1,  SIMPLE,      p,     ALL,  PRIMARY,       NULL,      NULL,    NULL, 331299, Using where; Using temporary; Using filesort
1,  SIMPLE,      b,     ref,  paymentFK,     paymentFK, 9,       p.id, 1,      Using where
我使用MySQL 5.1.34


查询中使用的
where
子句过滤掉
Payment
中的绝大多数行。我得到的印象是,MySQL在使用(高度选择性)
where
子句过滤结果集之前对结果集进行排序。我说的对吗?如果是,为什么会这样做?我已尝试分析这两个表,但没有更改查询计划。

首先,确保表上有适当的索引。假设您这样做了,但仍然比预期的慢,您可以将结果放入子查询中,而无需对其排序,然后将ORDER BY子句添加回:

SELECT * 
FROM (
   select * from Booking b
   join Payment p on b.paymentId = p.id
   where p.status = 3
)
ORDER BY nrOfPassengers
我不确定这会有多大帮助,因为当我查看执行计划时,它会添加一行,但它可能会更快


祝你好运。

我怀疑,问题是在你删除的不相关内容中有一个
TEXT
BLOB
列,它让MySQL冒险存储临时表的中间结果

在任何情况下,我们从执行计划中看到: 对于
Payment
表中的每一行,从磁盘中取出它,检查条件,如果
Booking
中的每一匹配行都为true,则将结果放入临时表中。按
nrOfPassengers
对整个表中的所有数据进行排序并输出。如果存在
Text
Blob
字段,则中间表存储并排序在磁盘上,因为MySQL无法预测表的大小

您可以(像往常一样)最大限度地减少磁盘操作。按照@ajreal的建议,在
status
列中添加索引。如果它是如此有选择性,您将不需要任何其他索引,但是如果您将您的
paymentFK
扩展到
(paymentId,nrOfPassengers)
则会更好。现在按如下方式重写查询:

SELECT p.*, b.*
FROM (
  select p.id as paymentId, b.id as bookingId
  from Booking b
  join Payment p on b.paymentId = p.id
  where p.status = 3
  order by b.nrOfPassengers
) as ids
JOIN Payment p ON ids.paymentId = p.id
JOIN Booking b ON ids.bookingId = b.id;

数据将按子查询顺序输出。

是否定义了索引?我有点惊讶,
paymentid
不是
booking
主键的一部分。这确实令人费解。是否可能是由于达到RAM限制而导致虚拟内存占用?请定义列状态的索引,然后再试一次。您认为您的查询有何帮助?您的思路实际上非常有趣。该表不包含任何
TEXT
BLOB
列。只有
VARCHAR
INT
BIGINT
DECIMAL
BIT
DATETIME
。但是,在
status
上添加索引会使原始查询和您的查询立即生效。我仍然无法理解为什么排序依据对原始查询的性能有如此大的影响。@ViktorDahl,第一个查询在排序之前不需要临时表来存储数据,并且无法预测第二个查询中表的大小,因为没有统计数据显示有多少行
p.status=3
SELECT p.*, b.*
FROM (
  select p.id as paymentId, b.id as bookingId
  from Booking b
  join Payment p on b.paymentId = p.id
  where p.status = 3
  order by b.nrOfPassengers
) as ids
JOIN Payment p ON ids.paymentId = p.id
JOIN Booking b ON ids.bookingId = b.id;