Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.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子查询总是执行文件排序_Mysql_Indexing_Innodb - Fatal编程技术网

Mysql子查询总是执行文件排序

Mysql子查询总是执行文件排序,mysql,indexing,innodb,Mysql,Indexing,Innodb,我有一个带有索引的table gamesplatform_pricehistory: (id\u应用程序,国家,更新) 这样做 explain select dateup from gamesplatform_pricehistory where id_app=1 and country=1 order by dateup desc limit 1 显示“使用位置;使用索引” 但是使用子查询: explain select app.id, (select dateup from

我有一个带有索引的table gamesplatform_pricehistory: (
id\u应用程序
国家
更新

这样做

explain select dateup from gamesplatform_pricehistory
    where id_app=1 and country=1
    order by dateup desc limit 1
显示“使用位置;使用索引”

但是使用子查询:

explain select app.id, (select dateup from gamesplatform_pricehistory
                           where id_app=app.id and country=1
                           order by dateup desc limit 1)
      from app where id > 0;
显示在何处使用;使用指数;使用文件排序

下面是一个sqlfiddle,它直接显示了问题:

具有数百万行的基准测试: (桌面游戏平台与app相同):

评估:0.8秒

SELECT sql_no_cache ( SELECT dateup FROM gamesplatform_pricehistory
                        WHERE id_app= games_platform.id AND country='229'
                        ORDER BY dateup DESC LIMIT 1
                    ) AS dateup
    FROM games_platform
    WHERE games_platform.id=2 

eval:0.0003s

使用文件排序并不一定是坏事。这个名字有点误导人。虽然它包含“文件”,但这并不意味着数据被写入硬盘上的任何位置。它仍然只是在内存中处理

从:

MySQL必须做一个额外的过程来了解如何按排序顺序检索行。排序是通过根据联接类型遍历所有行并存储与WHERE子句匹配的所有行的排序键和指向该行的指针来完成的。然后对键进行排序,并按排序顺序检索行。见第节

你知道为什么在你的查询中会发生这种情况,对吗?使用这种子查询是不好的风格,因为它是一个依赖的子查询。对于
app
表中的每一行,都会执行子查询。非常糟糕。使用
连接重写查询

select app.id,
gp.dateup
from app 
join gamesplatform_pricehistory gp on gp.id_app = app.id
where app.id > 0
and gp.country = 1
and gp.dateup = (SELECT MAX(dateup) FROM gamesplatform_pricehistory smgp WHERE smgp.id_app = gp.id_app AND smgp.country = 1)
;
这仍然使用依赖子查询,但是
explain
看起来更好:

| id |        select_type | table |  type | possible_keys |     key | key_len |                        ref | rows |                    Extra |
|----|--------------------|-------|-------|---------------|---------|---------|----------------------------|------|--------------------------|
|  1 |            PRIMARY |   app | index |       PRIMARY | PRIMARY |       4 |                     (null) |    2 | Using where; Using index |
|  1 |            PRIMARY |    gp |   ref |        id_app |  id_app |       5 |    db_2_034bc.app.id,const |    1 | Using where; Using index |
|  2 | DEPENDENT SUBQUERY |  smgp |   ref |        id_app |  id_app |       5 | db_2_034bc.gp.id_app,const |    1 |              Using index |
另一种重写方法是:

select app.id,
gp.dateup
from app 
LEFT join 
(SELECT id_app, MAX(dateup) AS dateup 
 FROM gamesplatform_pricehistory
 WHERE country = 1
 GROUP BY id_app
)gp on gp.id_app = app.id
where app.id > 0
;
这个解释看起来更好:

| id | select_type |                      table |  type | possible_keys |     key | key_len |    ref | rows |                    Extra |
|----|-------------|----------------------------|-------|---------------|---------|---------|--------|------|--------------------------|
|  1 |     PRIMARY |                        app | index |       PRIMARY | PRIMARY |       4 | (null) |    2 | Using where; Using index |
|  1 |     PRIMARY |                 <derived2> |   ALL |        (null) |  (null) |  (null) | (null) |    2 |                          |
|  2 |     DERIVED | gamesplatform_pricehistory | index |        (null) |  id_app |      13 | (null) |    2 | Using where; Using index |
| id |选择|类型|类型|可能的|键|键|列|参考|行|额外|
|----|-------------|----------------------------|-------|---------------|---------|---------|--------|------|--------------------------|
|1 | PRIMARY | app | index | PRIMARY | PRIMARY | 4 |(null)| 2 |使用where;使用索引|
|1 | PRIMARY | | ALL |(null)|(null)|(null)|(null)|(null)| 2 ||
|2 |派生|游戏平台|价格历史|索引|(null)| id |应用程序| 13 |(null)| 2 |使用where;使用索引|
这是一个完全没有依赖子查询的版本:

select app.id,
gp.dateup
from app 
left join gamesplatform_pricehistory gp on gp.id_app = app.id and country = 1
left join gamesplatform_pricehistory gp2 on gp.id_app = app.id and country = 1 and gp.dateup < gp2.dateup
where app.id > 0
and gp2.dateup is null
;
选择app.id,
全科医生
来自应用程序
左键加入游戏gp.id上的Platform_pricehistory gp\u app=app.id和country=1
左键加入游戏gp.id上的platform_pricehistory gp2\u app=app.id和country=1和gp.dateup0
并且gp2.dateup为空
;

它的工作原理是这样的:当
gp.dateup
达到最大值时,就没有
gp2.dateup

请提供
SHOW CREATE TABLE

其中一个综合指数可能会有所帮助:

INDEX(id_app, country, dateup)
INDEX(country, id_app, dateup)

你有没有试过用一张超过两行的桌子来做这个?如果只是一个小表,查询优化程序可能只会扫描整个表。是的,一个更复杂的查询,但是对于一个有数百万行的表和相同的子查询,仍然会做同样的事情,因为MySQL一次只能使用一个索引。我没有时间取消点击,但是你是否尝试过重写它以使用连接和分组依据?请参见下文,分组依据看起来很糟糕谢谢。子查询不会在与“where”匹配的每一行上执行?为什么子查询直接执行查询时使用filesort而不是filesort?这是我使用您的上一个请求得到的结果,组为:1 PRIMARY ALL NULL 118313 4 DERIVED gamesplatform_pricehistory range NULL id_app 5 NULL 373772 using where;当然,我的意思是为外部查询的每一行使用“是”组索引,匹配
where
。请注意,我做了一个
左连接
,我假设您想要返回结果,即使
gamesplatform_pricehistory
表中没有匹配项。因为你的
应用程序
表上没有合适的索引,所以它会扫描整个表。你解释的第二部分看起来不错。在你的问题中包括这些信息。很难在评论中读到,左键连接。是的,即使在pricehistory中没有匹配项,我也希望得到结果。我在应用程序上有一个合适的索引,在id上有一个主键,这是这个requeston sqlfiddle上唯一使用的列。你可以看到索引:ALTER TABLE
gamesplatform\u pricehistory
添加主键(
id
),ADD key
id\u app
id\u app
country
dateup
);
INDEX(id_app, country, dateup)
INDEX(country, id_app, dateup)