繁体   English   中英

MySQL OUTER LEFT JOIN性能

[英]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次左右-可能比原始数据要大得多。

真正的问题是为什么您需要所有这些信息在应用程序的内存中。 您拥有数据库,只需在需要时取回所需的内容即可。 您熟悉limitoffset吗?这些可能正是您真正想要的。

我认为您可以使用此:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM