使用子查询优化MySQL JOIN

时间:2015-05-20 18:32:13

标签: mysql query-optimization

我当前的MySQL查询非常慢。 我正在寻找优化它的方法。

我有一张桌子上有Steam游戏的赠品(12.711条记录)。

((char*)5)

我还有一个用户已经拥有Steam游戏的桌子(130.117条记录)。

CREATE TABLE IF NOT EXISTS `giveaway` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `creatorid` bigint(20) unsigned NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `appid` int(10) DEFAULT NULL,
  `packageid` int(10) DEFAULT NULL,
  `gamename` varchar(256) NOT NULL,
  `gametype` varchar(64) NOT NULL,
  `copies` int(3) unsigned NOT NULL,
  `multiplier` float unsigned NOT NULL DEFAULT '1',
  `closed` timestamp NULL DEFAULT NULL,
  `winnerid` bigint(20) unsigned DEFAULT NULL,
  `cancelled` tinyint(1) unsigned DEFAULT NULL,
  `noentry` tinyint(1) unsigned DEFAULT NULL,
  `url` varchar(256) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `winnerid` (`winnerid`),
  KEY `creatorid` (`creatorid`),
  KEY `packageid` (`packageid`),
  KEY `appid` (`appid`),
  KEY `gametype` (`gametype`)
) ENGINE=InnoDB AUTO_INCREMENT=12003 DEFAULT CHARSET=utf8;

INSERT INTO `giveaway` (`id`, `creatorid`, `created`, `appid`, `packageid`, `gamename`, `gametype`, `copies`, `multiplier`, `closed`, `winnerid`, `cancelled`, `noentry`, `url`) VALUES
    (148, 76561198043198608, '2014-08-05 15:41:12', 72200, NULL, 'Universe Sandbox', 'bundle', 1, 1, '2014-08-05 15:41:29', 76561198051609534, NULL, NULL, 'http://www.steamgifts.com/giveaway/ZvyXL/universe-sandbox'),
    (149, 76561197993840952, '2014-08-05 15:41:49', 287860, NULL, '8-Bit Commando', 'bundle', 1, 1, '2014-08-12 18:54:15', 76561198001912161, NULL, NULL, 'http://www.steamgifts.com/giveaway/qlFrc/8-bit-commando'),
    (150, 76561198043198608, '2014-08-05 15:42:09', 212010, NULL, 'Galaxy on Fire 2 Full HD', 'bundle', 1, 1, '2014-08-05 15:43:17', 76561198031159289, NULL, NULL, 'http://www.steamgifts.com/giveaway/eyNT1/galaxy-on-fire-2-full-hd');

我想展示所有赠品,并能够表明用户是否已经拥有它。

我可以通过将赠品中的appid与当前用户的 steam_ownedgames 中的appid进行比较来获取此信息。

输出示例:

CREATE TABLE IF NOT EXISTS `steam_ownedgames` (
  `steamid` bigint(20) unsigned NOT NULL,
  `appid` bigint(20) unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY `steamid` (`steamid`),
  KEY `appid` (`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `steam_ownedgames` (`steamid`, `appid`, `last_update`) VALUES
    (76561198112359563, 4000, '2015-05-20 18:03:10'),
    (76561198112359563, 2990, '2015-05-20 18:03:10'),
    (76561198112359563, 12200, '2015-05-20 18:03:10'),
    (76561198112359563, 12210, '2015-05-20 18:03:10'),
    (76561198112359563, 29800, '2015-05-20 18:03:10'),
    (76561198112359563, 9870, '2015-05-20 18:03:10'),
    (76561198112359563, 34900, '2015-05-20 18:03:10'),
    (76561198112359563, 11390, '2015-05-20 18:03:10'),
    (76561198112359563, 23490, '2015-05-20 18:03:10'),
    (76561198112359563, 18820, '2015-05-20 18:03:10'),
    (76561198112359563, 24960, '2015-05-20 18:03:10'),
    (76561198112359563, 43110, '2015-05-20 18:03:10'),
    (76561198112359563, 46410, '2015-05-20 18:03:10'),
    (76561198112359563, 50620, '2015-05-20 18:03:10'),
    (76561198112359563, 70300, '2015-05-20 18:03:10'),
    (76561198112359563, 63800, '2015-05-20 18:03:10');

我通过以下查询获得了我想要的信息。

giveawayid  owned   appid   gamename
12810       12810   264060  Full Bore
12809       \N      263100  9.03m
12808       12808   107200  Space Pirates and Zombies
12807       12807   231910  Leisure Suit Larry in the Land of the Lounge Lizards: Reloaded
12806       \N      278620  TinyKeep
12805       \N      315430  Polarity
12804       12804   341060  The Lady

然而,这个很慢,需要27秒才能完成。随着数据库的增长,时间越来越快。

谁有关于如何更好地进行优化的建议?

1 个答案:

答案 0 :(得分:1)

您不需要该子选择。起初它有点不直观,但如果你只想加入一个子集,这是标准的方法。这样做是抓取所有赠品记录并找到具有特定用户(steamid)的同一游戏(appid)的任何steam_ownedgames记录。

SELECT giveaway.id as giveawayid
   , appid, gamename
   , sog.last_update AS ownedSince
FROM giveaway 
LEFT JOIN steam_ownedgames AS sog
        ON giveaway.appid = sog.appid
        AND sog.steamid = 76561197962290563
ORDER BY created DESC, giveaway.id DESC 
LIMIT 0, 500 
;

它相当于这个(下面),但允许利用指数。 实际上,在某些情况下,下面的内容可能会更快,但它会高度依赖于表格中的特定数据。例如:如果用户只有3个游戏,则无法编制的配对可能比1000个用户拥有的游戏的索引配对更快。

SELECT giveaway.id as giveawayid
   , appid, gamename
   , sog.last_update AS ownedSince
FROM giveaway 
LEFT JOIN (
   SELECT * 
   FROM steam_ownedgames 
   WHERE steamid = 76561197962290563
  ) AS sog
  ON giveaway.appid = sog.appid
ORDER BY created DESC, giveaway.id DESC 
LIMIT 0, 500 
;

在这个例子中,如果不拥有,ownSince将为null;但是在steam_owned游戏中的任何字段都应该足够(只要它通常不能为空)。