【问题标题】:MySQL: How to prevent filesort with index for column used in ORDER BYMySQL:如何使用 ORDER BY 中使用的列的索引来防止文件排序
【发布时间】:2015-06-08 14:22:00
【问题描述】:

我正在尝试针对当前非常慢的查询优化 MySQL 数据库:

SELECT  Listing.*,  PrimaryPhoto.* 
 FROM listings AS Listing  
 LEFT JOIN file_storage AS PrimaryPhoto  
 ON (PrimaryPhoto.foreign_key  =  Listing.ID  
 AND  PrimaryPhoto.model  = 'PrimaryListingPhoto') 
 WHERE  Listing.rent  >= 0 
 AND  Listing.rent  <= 5000 
 AND  Listing.beds  >= 1 
 AND  Listing.is_active  = '1' 
 ORDER BY Listing.modified  DESC

我在listings 表中添加了几个索引... ...这是file_storage 表的索引... ...但它仍然很慢!运行 20 多秒。

EXPLAIN 告诉我 filesort 正在被使用:

我认为我可以通过为 WHEREORDER BY 子句中提到的所有 4 列添加索引来防止 filesort。但它没有奏效。

我做错了吗?或者,也许我正在寻找错误的地方来加速这个查询。

更新 这是两个表的架构:

CREATE TABLE IF NOT EXISTS `listings` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT 'ID of user who owns this listing', `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `address` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Street address (w/o postal code)', `lat` decimal(10,8) DEFAULT NULL, `lng` decimal(11,8) DEFAULT NULL, `postal_code` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `description` text COLLATE utf8_unicode_ci NOT NULL, `rent` int(11) NOT NULL COMMENT 'Monthly rental price in CAD', `lease_length` int(11) DEFAULT NULL COMMENT '# of months of lease', `date_available` date DEFAULT NULL COMMENT 'Day the listing is available', `neighborhood_id` int(11) NOT NULL, `beds` int(11) NOT NULL COMMENT '# of bedrooms', `baths` int(11) NOT NULL COMMENT '# of bathrooms', `sq_ft` int(11) DEFAULT NULL COMMENT '# of square footage', `fridge` tinyint(1) NOT NULL, `stove` tinyint(1) NOT NULL, `dishwasher` tinyint(1) NOT NULL, `ac` tinyint(1) NOT NULL, `furnished` tinyint(1) NOT NULL, `laundry` tinyint(1) NOT NULL, `balcony` tinyint(1) NOT NULL, `patio` tinyint(1) NOT NULL, `yard` tinyint(1) NOT NULL, `pool` tinyint(1) NOT NULL, `doorman` tinyint(1) NOT NULL, `security` tinyint(1) NOT NULL, `gym` tinyint(1) NOT NULL, `parking` tinyint(1) NOT NULL, `wheelchair` tinyint(1) NOT NULL, `inc_heat` tinyint(1) NOT NULL COMMENT 'does the rent include heat?', `inc_water` tinyint(1) NOT NULL COMMENT 'doest the rent include water?', `inc_internet` tinyint(1) NOT NULL COMMENT 'does the rent include internet?', `inc_cable` tinyint(1) NOT NULL COMMENT 'does the rent include cable?', `cats` tinyint(1) NOT NULL COMMENT 'are cats allowed?', `small_dogs` tinyint(1) NOT NULL COMMENT 'are small dogs allowed?', `big_dogs` tinyint(1) NOT NULL COMMENT 'are big dogs allowed?', `is_active` tinyint(1) NOT NULL COMMENT 'is the listing active?', `is_hot` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'hot list', `source_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `source_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, PRIMARY KEY (`ID`), KEY `user_id` (`user_id`), KEY `is_active` (`is_active`), KEY `rent` (`rent`), KEY `rent_beds_is_active` (`rent`,`beds`,`is_active`), KEY `modified` (`modified`), KEY `rent_beds_active_modified` (`rent`,`beds`,`is_active`,`modified`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3012 ;

CREATE TABLE IF NOT EXISTS `file_storage` ( `id` varchar(36) COLLATE utf8_unicode_ci NOT NULL, `user_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL, `foreign_key` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL, `model` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL, `filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `filesize` int(16) DEFAULT NULL, `mime_type` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `extension` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL, `hash` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL, `path` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `adapter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Gaufrette Storage Adapter Class', `created` datetime DEFAULT NULL, `modified` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `foreign_key` (`foreign_key`), KEY `model_foreign_key` (`model`,`foreign_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

【问题讨论】:

  • 这个查询产生多少结果?
  • @eggyal 在生产中,目前将返回 975 个结果
  • 我看到在你的file_storage 表中你有一个复合索引(模型,foreign_key)。尝试仅在 model 上添加索引。
  • @Daan 我只为model 添加了一个索引,但它似乎没有多大作用。基数是 20。
  • 两个表有多少列和记录?你能张贴表格吗?

标签: php mysql sql join query-optimization


【解决方案1】:

这是您的查询:

SELECT  Listing.*,  PrimaryPhoto.* 
FROM listings AS Listing LEFT JOIN
     file_storage AS PrimaryPhoto  
     ON PrimaryPhoto.foreign_key  =  Listing.ID  AND 
        PrimaryPhoto.model  = 'PrimaryListingPhoto'
WHERE Listing.rent >= 0 AND  Listing.rent  <= 5000 AND
      Listing.beds  >= 1 AND
      Listing.is_active  = '1' 
ORDER BY Listing.modified  DESC

试试这个复合索引(键的顺序很重要):Listing(beds, is_active, modified, rent)where 上的完整索引(即beds, is_active, rent)order by 没有帮助。这个可能。另外,您需要file_storage(foreign_key, model) 上的索引。

【讨论】:

  • 你看到我对上面Daan回答的评论了吗?很好奇这是否与您的推荐有交互作用。
  • PrimaryPhoto.model = 'PrimaryListingPhoto' 移动到where 子句会将join 更改为内部连接。那是一个不同的查询。
  • 谢谢!您是如何确定索引列的顺序的?
  • @SDP 。 . .从where 中的相等条件开始。然后,从whereorder by 中选择一个不等式。如果是后者,请保持手指交叉,以便使用它。
【解决方案2】:

删除 PrimaryPhoto.model 上的索引并删除连接将其添加到 where 子句。您的查询应如下所示:

SELECT  Listing.*,  PrimaryPhoto.* 
 FROM listings AS Listing  
 LEFT JOIN file_storage AS PrimaryPhoto  
 ON PrimaryPhoto.foreign_key  =  Listing.ID
 WHERE  Listing.rent  >= 0 
 AND  Listing.rent  <= 5000 
 AND  Listing.beds  >= 1 
 AND  Listing.is_active  = '1' 
 AND  PrimaryPhoto.model  = 'PrimaryListingPhoto'
 ORDER BY Listing.modified  DESC

也尽量不要选择*,只选择必要的列。

【讨论】:

  • 有趣。你能说几句话来解释将ON 条件移动到WHERE 的目标吗?这个查询是由一个框架(CakePHP)生成的,所以理解更高的目的将帮助我,同时我把它弄成我想做的事。
  • 当您在 JOIN 中执行此操作时,规划器可能必须从表中选择,按“True”部分过滤,然后加入结果集。要查看大量数据,并且它不能有效地使用索引。如果您在 WHERE 子句中执行此操作,则规划器正在选择更有效的路线(即预过滤数据集)。 (这个故事中的索引是 PrimaryPhoto.foreign_key)
  • 我仍在研究是否有办法使用 CakePHP 自定义 ON 条件。但与此同时,我抢先将PrimaryPhoto.model = 'PrimaryListingPhoto' 添加到WHERE 子句中,这似乎有很大帮助! MySQL 是否足够聪明,可以在它们都存在时使用 WHERE 而不是 ON?您对为什么它可能已经工作有任何其他想法(在删除有问题的ON 之前)?
猜你喜欢
  • 2010-10-18
  • 1970-01-01
  • 2012-07-31
  • 1970-01-01
  • 2011-09-29
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
相关资源
最近更新 更多