MySQL JOIN和ORDER BY - 性能问题

时间:2015-12-05 02:18:16

标签: mysql performance database-performance

我有这个问题让我疯狂了很长一段时间。它有3个表(最初它有更多,但我隔离了性能问题),1个基表,1个产品表添加更多数据,1个产品类型。 产品类型表包含"最大年龄"列,表示我想要获取的行的最大年龄(任何旧的都被认为是#34;存档"),并且其值根据产品类型而不同。 我糟糕的性能查询是这样的,250,000行基表需要50秒:

from pyspark.mllib.regression import LabeledPoint
import numpy as np

a = LabeledPoint(0, [1,2,3])
b = LabeledPoint(0, [3,1,2])
c = LabeledPoint(a.label, np.concatenate((a.features, b.features), axis=0))

print c # LabeledPoint(0.0, [1.0,2.0,3.0,3.0,1.0,2.0])

以下是此查询的EXPLAIN:

(select d_baseservices.ID
from d_baseservices    
inner join d_products on d_baseservices.ServiceID = d_products.ServiceID
inner join md_prodtypes on d_products.ProdType = md_prodtypes.ProdType
where
(d_baseservices.CreationDate > (curdate() - INTERVAL md_prodtypes.MaxAge DAY))
order by CreationDate desc 
limit 750);

几天前我发现了一条线索,当我能够确定将查询限制为750条记录会导致速度变快,但751会带来糟糕的表现。

我尝试创建多种索引,但没有成功。 我尝试删除对MAX_AGE和curdate函数的引用,只设置一个固定值,但由于查询现在需要20秒,因此收效甚微:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  md_prodtypes    index   PRIMARY,ProdType_UNIQUE,ID_MAX_AGE  MAX_AGE 5       23  Using index; Using temporary; Using filesort
1   SIMPLE  d_products  ref PRIMARY,ServiceID_UNIQUE,fk_Products_BaseServices1,fk_d_products_md_prodtypes1  fk_d_products_md_prodtypes1 4   combina.md_prodtypes.ProdType   8625    
1   SIMPLE  d_baseservices  eq_ref  PRIMARY,CreationDateDesc_index,CreationDate_index   PRIMARY 8   combina.d_products.ServiceID    1   Using where

并且EXPLAIN命令输出:

(select d_baseservices.ID
from d_baseservices    
inner join d_products on d_baseservices.ServiceID = d_products.ServiceID
inner join md_prodtypes on d_products.ProdType = md_prodtypes.ProdType
where
(d_baseservices.CreationDate > '2015-09-21 19:02:25')
order by CreationDate desc 
limit 750);

有人可以帮忙吗?我被困了将近一个月

2 个答案:

答案 0 :(得分:2)

如果不了解更多有关您拥有的特定数据(每个表中有多少行,您希望查询返回多少行,数据值的分布等),很难确切地说要做什么),但我会做一些有根据的猜测,并希望指出你正确的方向。

首先解释为什么从查询中取出md_prodtypes.MaxAge大大减少了运行时间:在更改之前,数据库根本没有能力使用索引进行过滤,因为为了查看行是否适合包含加入这三个表,以便将第一个表中的CreationDate与第三个表中的MaxAge进行比较。您可以添加任何索引来关联这两个值。您强制数据库引擎查看每一行

对于750幻数 - 我猜测过去750结果数据库必须分页数据,或者根据特定MySQL配置文件中的值来达到其他内存限制。我不会过多地读到那个750号码。

最后,我想指出你的第二个查询的EXPLAIN有点奇怪,因为它显示md_prodtypes作为第一个表,尽管你已经{{1} } MaxAge之外。这意味着数据库从WHERE开始,然后向上移动到md_prodtypes,最后到d_products,然后根据日期进行过滤。我猜你是否期望它首先在日期过滤,然后只有当它决定要包括哪些baseservices记录时才加入。用你提供的信息知道为什么会发生这种情况是不可能的。也许你错过了一个索引 另一种可能性可能与您的d_baseservices列中的差异有关。让我通过示例解释一下:假设您有一个用户表,每个用户都有一个CreationDate列,可以是genderf。让我们假设我们有50%/ 50%的女性和男性分开。现在,如果您在列m上添加索引并执行由gender过滤的查询,期望索引将过滤掉一半的记录,那么您会惊讶地看到该数据库将完全忽略索引并只扫描表。原因在于,如果您知道索引不足以过滤掉(替代方案是从索引到主表数据不断跳跃),那么读取整个表格会更便宜。在您的情况下,如果WHERE gender='f'列上的WHERE没有过滤掉足够的记录,那么即使您有一个索引,它也不会被使用。

答案 1 :(得分:0)

日期不变......

INDEX(CreationDate)

这将鼓励优化器从可以过滤的表开始。此外,由于ORDER BY位于同一字段,因此WHEREORDER BYLIMIT可以同时完成。

否则,它必须读取所有3个表中的所有相关记录,对它们进行排序,然后发送750(或751)个表。

使用MAX_AGE ...

现在优化器不会知道如上所述更好还是找到所有行,对它们进行排序,然后传递LIMIT。

相关问题