2012-03-12 49 views
0
SELECT citing.article_id as citing, lac_a.year, r.id_when_cited, cited_issue.country, citing.num_citations 
FROM isi_lac_authored_articles as lac_a 
    JOIN isi_articles citing ON (lac_a.article_id = citing.article_id) 
    JOIN isi_citation_references r ON (citing.article_id = r.article_id) 
    JOIN isi_articles cited ON (cited.id_when_cited = r.id_when_cited) 
    JOIN isi_issues cited_issue ON (cited.issue_id = cited_issue.issue_id); 

我有所有被加入的领域的索引。如何优化多个连接(已经有索引)的查询?

有什么我可以做的吗?我的表很大(大约有100万条记录,参考表有5亿条记录,文章表有25万条记录)。

这就是EXPLAIN不得不说:

+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
| id | select_type | table  | type | possible_keys               | key         | key_len | ref       | rows | Extra  | 
+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
| 1 | SIMPLE  | cited_issue | ALL | NULL                  | NULL         | NULL | NULL       | 1156856 |    | 
| 1 | SIMPLE  | cited  | ref | isi_articles_id_when_cited,isi_articles_issue_id       | isi_articles_issue_id     | 49  | func       |  19 | Using where | 
| 1 | SIMPLE  | r   | ref | isi_citation_references_article_id,isi_citation_references_id_when_cited | isi_citation_references_id_when_cited | 17  | mimir_dev.cited.id_when_cited |  4 | Using where | 
| 1 | SIMPLE  | lac_a  | eq_ref | PRIMARY                 | PRIMARY        | 16  | mimir_dev.r.article_id  |  1 |    | 
| 1 | SIMPLE  | citing  | eq_ref | PRIMARY                 | PRIMARY        | 16  | mimir_dev.r.article_id  |  1 |    | 
+----+-------------+-------------+--------+--------------------------------------------------------------------------+---------------------------------------+---------+-------------------------------+---------+-------------+ 
5 rows in set (0.07 sec) 
+0

编辑:增加说明输出 – pocketfullofcheese 2012-03-12 07:52:00

+1

你使用什么数据库类型?这是一个非常简单的SQL语句。你在使用myisam还是innodb? – 2012-03-12 07:57:28

+0

myisam。它简单的SQL,但表格很大。 EXPLAIN输出的第一行有1M行...我可以通过分割我的查询来避免这种类型的事情吗?或者是其他东西? – pocketfullofcheese 2012-03-12 08:01:08

回答

0

如果你真的需要所有返回的数据,我建议两两件事:

  1. 你,大概,知道数据比MySQL更好,你可以尝试利用它的优势,如果MySQL是不正确在其假设中。目前,MySQL认为在开始时更容易全面扫描整个isi_issues表,并且如果结果真的会包含所有问题,那么假设是正确的。但是,如果结果中不存在许多问题,则可能需要强制您认为更加正确的另一个连接顺序。这是你,谁知道哪个表应用最强的限制,哪些是最小的到完全扫描(因为没有WHERE子句,你无论如何都需要全面扫描一些东西)。

  2. 您可以通过覆盖索引(即包含足够数据本身且不需要触摸行数据的索引)获利。例如,isi_articles和(article_id,year)isi_lac_authored_articles上的索引(article_id,num_citations)和isi_issues上的(国家)将会显着加快该查询,只要索引适合内存,但从另一方面来看,会让你的索引变大并且稍微慢一点的插入到表中。

+0

在第1点。我知道它不会被使用所有问题。我如何强制它最后加入JOIN?我想要全面扫描的唯一表格是第一个(isi_lac_authored_articles)。 – pocketfullofcheese 2012-03-12 16:07:58

+0

@pocketfullofcheese,看看在MySQL文档中的'STRAIGHT_JOIN':http://dev.mysql.com/doc/refman/5.1/en/select.html – newtover 2012-03-12 16:12:30

+0

我试过了,但它似乎并没有正在变得更快。我如何检查发生了什么?有没有办法检查查询的进度? – pocketfullofcheese 2012-03-12 23:18:13

0

我认为这是你能做的最好的。我的意思是至少它没有使用嵌套/多个查询。你应该在sql上做一点基准。你至少可以尽可能地限制你的结果。 15-30行的返回设置是非常好的每页(这取决于应用程序,但15-30对我来说是公差范围)

我相信mySQL(phpMyAdmin,控制台,GUI无论)他们返回一些排序“执行时间”,即执行查询所花费的时间。将其与使用服务器端代码的查询基准进行比较。然后将其与使用服务器端代码运行的查询进行比较,然后将其与您的应用程序界面一起输出。

通过这个,你可以看到你的瓶颈在哪里 - 这是你优化的地方。

+0

我只是运行这个服务器端,它的数据分析。但我需要多次运行它(具有不同的变化)。问题是,查询需要数小时。但是我不确定哪部分需要这么长时间,或者我可以做些什么来加速它(例如,将它分成多个查询并将结果保存在临时表中) – pocketfullofcheese 2012-03-12 07:51:47

+0

如果这是您唯一的查询,我建议分批进行测试,例如每次少数测试,并检查执行所需的时间。此查询返回多少行?这个问题可能是因为你只是有一堆巨大的数据,并且每个查询返回大量的结果。 – Joseph 2012-03-12 08:00:44

+0

是的,它将返回3M行。我需要耐心吗? – pocketfullofcheese 2012-03-12 08:02:30

0

除非将查询结果输入到某个其他查询或系统,否则返回那么多(3M)行是没用的。每个查询返回一个可接受数量的行(比如1000)用于可视化会很聪明。

0

看你的SQL - 缺乏一个WHERE子句意味着它是由拉的所有行:

JOIN isi_issues cited_issue ON (cited.issue_id = cited_issue.issue_id) 

你可以看看分割大isi_issues表,这将让MySQL的执行有点快(更小的文件更容易处理)

或者,您也可以循环语句并使用LIMIT子句。

LIMIT 0,100000 然后 LIMIT 100001,200000

这将让报表运行更快,你可以处理批量数据。

+0

我不这么认为,在这里使用'LIMIT'是一个好主意,因为要输出100001行,200000 MySQL需要重新读取第0,1,0000行。 – newtover 2012-03-12 09:41:44