连接多个表会使查询运行时间过长

时间:2011-11-24 20:14:12

标签: mysql sql

我有几个表,包含(a.o.)以下字段:

tweets:
--------------------------
tweet_id ticker created_at
--------------------------
1        1      1298063318
2        1      1298053197

stocks:
---------------------------------
ticker date        close volume
---------------------------------
1      1313013600  12.25 40370600
1      1312927200  11.60 37281300

wiki:
-----------------------
ticker date       views
-----------------------
1      1296514800   550
1      1296601200   504

我希望每天编辑推文,关闭,数量和视图的概述(对于由ticker = 1标识的行)。推文表是领先的,这意味着如果有一个没有推文的日期,那天的关闭,数量和视图无关紧要。换句话说,我希望查询的输出如下:

-------------------------------------
date        tweets close volume views
-------------------------------------
2011-02-13  4533   12.25 40370600 550
2011-02-14  6534   11.60 53543564 340
2011-02-16  5333   13.10 56464333 664

在此示例输出中,2011-02-15没有推文,因此不需要当天的其余数据。到目前为止,我的询问是:

SELECT 
  DATE_FORMAT(FROM_UNIXTIME(tweets.created_at), '%Y-%m-%d') AS date, 
  COUNT(tweets.tweet_id) AS tweets,
  stocks.close,
  stocks.volume,
  wiki.views
FROM tweets
LEFT JOIN stocks ON tweets.ticker = stocks.ticker
LEFT JOIN wiki ON tweets.ticker = wiki.ticker
WHERE tweets.ticker = 1
GROUP BY date
ORDER BY date ASC

有人可以验证此查询是否正确吗?它不会遇到任何错误,但会冻结我的电脑。也许我应该在这里或那里设置索引,可能在“自动收报机”列上?

[编辑]

根据要求,表定义:

CREATE TABLE `stocks` (
  `ticker` int(3) NOT NULL,
  `date` int(10) NOT NULL,
  `open` decimal(8,2) NOT NULL,
  `high` decimal(8,2) NOT NULL,
  `low` decimal(8,2) NOT NULL,
  `close` decimal(8,2) NOT NULL,
  `volume` int(8) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `tweets` (
  `tweet_id` int(11) NOT NULL AUTO_INCREMENT,
  `ticker` varchar(5) NOT NULL,
  `id_str` varchar(18) NOT NULL,
  `created_at` int(10) NOT NULL,
  `from_user` int(11) NOT NULL,
  `text` text NOT NULL,
  PRIMARY KEY (`tweet_id`),
  KEY `id_str` (`id_str`),
  KEY `from_user` (`from_user`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE `wiki` (
  `ticker` int(3) NOT NULL,
  `date` int(11) NOT NULL,
  `views` int(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

我希望这会有所帮助。

3 个答案:

答案 0 :(得分:2)

你是关于指数的,没有股票代码索引,你必须在所有表中进行搜索,如果它们很大,那将需要很多时间。

我建议您至少每隔一段时间打开logging of all queries that run without index,以便在数据增加时查找已经慢的查询。

如果发现问题很慢,请检查[EXPLAIN SELECT ...][2]的查询,了解如何解释结果(不容易但很重要),以了解放置新索引的位置。

答案 1 :(得分:1)

我认为其中一个问题是日期计算

DATE_FORMAT(FROM_UNIXTIME(tweets.created_at), '%Y-%m-%d') date

尝试将此字段添加到tweets表中以避免CPU消耗

编辑: 你可以使用这样的东西

CREATE TABLE `stocks` (
  `ticker` int(3) NOT NULL,
  `date` int(10) NOT NULL,
  `open` decimal(8,2) NOT NULL,
  `high` decimal(8,2) NOT NULL,
  `low` decimal(8,2) NOT NULL,
  `close` decimal(8,2) NOT NULL,
  `volume` int(8) NOT NULL,
  `day_date` varchar(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `tweets` (
  `tweet_id` int(11) NOT NULL AUTO_INCREMENT,
  `ticker` varchar(5) NOT NULL,
  `id_str` varchar(18) NOT NULL,
  `created_at` int(10) NOT NULL,
  `from_user` int(11) NOT NULL,
  `text` text NOT NULL,
  `day_date` varchar(10) NOT NULL,
  PRIMARY KEY (`tweet_id`),
  KEY `id_str` (`id_str`),
  KEY `from_user` (`from_user`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE `wiki` (
  `ticker` int(3) NOT NULL,
  `date` int(11) NOT NULL,
  `views` int(6) NOT NULL,
  `day_date` varchar(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


SELECT 
tweets.day_date AS date, 
COUNT(tweets.tweet_id) AS tweets,
stocks.close as close,
stocks.volume as volume,
wiki.views as views
FROM tweets
LEFT JOIN stocks ON tweets.ticker = stocks.ticker 
                and tweets.day_date = stocks.day_date
LEFT JOIN wiki ON tweets.ticker = wiki.ticker
              and tweets.day_date = wiki.day_date
WHERE tweets.ticker = 1
GROUP BY date, close, volume, views
ORDER BY date ASC

答案 2 :(得分:1)

相信你应该检查表之间的连接。您的查询未指明哪些股票行(或维基行)与推文日期匹配。根据示例数据,对具有相同ticker_id的所有股票和维基行进行匹配。

对于一个股票代码,股票和维基表在某一天只有一行吗?假设是这种情况,更多逻辑查询将如下所示:

SELECT 
  DATE_FORMAT(FROM_UNIXTIME(t.created_at), '%Y-%m-%d') AS date, 
  COUNT(t.tweet_id) AS tweets,
  s.close,
  s.volume,
  w.views
FROM tweets t
  LEFT JOIN stocks s ON t.ticker = s.ticker 
       and FROM_UNIXTIME(t.created_at,'%Y-%m-%d')=FROM_UNIXTIME(s.date,'%Y-%m-%d')
  LEFT JOIN wiki w ON t.ticker = w.ticker
       and FROM_UNIXTIME(t.created_at,'%Y-%m-%d')=FROM_UNIXTIME(w.date,'%Y-%m-%d')
WHERE tweets.ticker = 1
GROUP BY date, s.close, s.volume, w.views
ORDER BY date ASC

如果某个股票代码在某一天的股票/维基中有多行,您还需要将聚合函数应用于这些列,并将COUNT(t.tweet_id)更改为COUNT(不同的t.created_at)