[英]MySQL OUTER LEFT JOIN performance
我正在更新现有的基于Web的清单系统,该系统从MySQL数据库中提取数据。 存储的数据的主要结构是具有一对多关系的“项目”和“标签”(项目可以具有多个对应的标签)
现有的数据前端系统是一个Backbone.js应用程序,该应用程序在登录时提取整个数据存储区,并在内存中处理该数据,并在必要时通过RESTful接口将其提交回数据库。 (这不是我本来要设计系统的方式,但是现在它已成为Backbone和Spine应用程序中的常见模式,以及大多数教程和书籍如何教授这些框架)。
为了提供由前端执行的初始提取,以捕获整个数据集(此时约有1000个项目和10,000个项目标签),后端对项目表执行SELECT查询,然后对标签进行后续SELECT查询表中提取的每个项目。 表现很糟糕。 我认为可以通过JOIN进行改进,弄清楚一个选择查询优于1000个。以下查询获取我需要的数据,但是即使在我的本地开发服务器上执行也要花费15秒以上的时间。 是什么赋予了? 我们是否可以在不设置其他基础架构(例如缓存键值存储)的情况下改进此系统或查询?
SELECT items.*, itemtags.id as `tag_id`, itemtags.tag, itemtags.type
FROM items LEFT OUTER JOIN
itemtags
ON items.id = itemtags.item_id
ORDER BY items.id;
表结构如下:
CREATE TABLE `items` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`num` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
`length_inches` int(10) unsigned DEFAULT NULL,
`length_feet` int(10) unsigned DEFAULT NULL,
`width_inches` int(10) unsigned DEFAULT NULL,
`width_feet` int(10) unsigned DEFAULT NULL,
`height_inches` int(10) unsigned DEFAULT NULL,
`height_feet` int(10) unsigned DEFAULT NULL,
`depth_inches` int(10) unsigned DEFAULT NULL,
`depth_feet` int(10) unsigned DEFAULT NULL,
`retail_price` int(10) unsigned DEFAULT NULL,
`discount` int(10) unsigned DEFAULT NULL,
`decorator_price` int(10) unsigned DEFAULT NULL,
`new_price` int(10) unsigned DEFAULT NULL,
`sold` int(10) unsigned NOT NULL,
`push_date` int(10) unsigned DEFAULT NULL,
`updated` int(10) unsigned NOT NULL,
`created` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1747 DEFAULT CHARSET=latin1;
CREATE TABLE `itemtags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`item_id` int(10) unsigned NOT NULL,
`tag` varchar(100) NOT NULL,
`type` varchar(100) NOT NULL,
`created` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=61474 DEFAULT CHARSET=latin1;
在性能方面,您可能没有进行同类比较。
SQL查询完全在做以下事情:
items.id
对结果排序 原始版本是否同时执行所有这三个操作并等待它们完成?
我的猜测是,原始代码会按您想要的顺序拉回项目,然后仅在任意给定时间拉动少数实际需要的标签。
此外,尚不清楚items.*
数据的大小。 制定查询的方式,您将每个项目的查询次数拉了10次左右-可能比原始数据要大得多。
真正的问题是为什么您需要所有这些信息在应用程序的内存中。 您拥有数据库,只需在需要时取回所需的内容即可。 您熟悉limit
和offset
吗?这些可能正是您真正想要的。
我认为您可以使用此:
SELECT *, a.id as `tag_id`, a.tag, a.type
FROM items LEFT OUTER JOIN
(SELECT id, item_id, tag, type from itemtags ORDER BY 1,2,3) a
ON items.id = a.item_id
ORDER BY items.id;
我并没有做太多改变,只是别名。 a并不表示任何重要意义。
我没有填写表格,但您原来的查询用了4毫秒,我的查询用了1毫秒。
http://sqlfiddle.com/#!2/b9551/6
无论您的数据集中有什么内容,您的应用程序都可以提取整个数据存储。 由于数据存储和数据集不是同义词。
您也没有任何indexes
。 您应该在ID, ITEM_ID
上放置索引ID, ITEM_ID
以优化表以更快地返回结果。 我在子查询中创建了一个索引,其order by
。 希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.