如何使用多个连接(已有索引)优化查询?

时间:2012-03-12 05:55:17

标签: mysql optimization

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);

我在所有正在加入的字段上都有索引。

我能做些什么吗?我的表很大(大约1百万条记录,参考表有5亿条记录,文章表有2500万条记录)。

这就是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)

4 个答案:

答案 0 :(得分:0)

我认为这是你能做的最好的事情。我的意思是至少它不使用嵌套/多个查询。你应该对sql做一点基准测试。你至少可以限制你的结果。每页15-30行的返回集非常精细(这取决于应用程序,但对我来说15-30是容差范围)

我相信mySQL(phpMyAdmin,控制台,GUI等)他们会返回某种“执行时间”,这是查询处理所花费的时间。使用服务器端代码将其与查询基准进行比较。然后将其与使用服务器端代码运行的查询进行比较,然后将其与之后包含的应用程序界面一起输出。

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

答案 1 :(得分:0)

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

答案 2 :(得分: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

这将使语句更快地运行,您可以批量处理数据。

答案 3 :(得分:0)

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

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

  2. 您可以从覆盖索引中获利(即索引本身包含足够的数据而不需要触及行数据)。例如,isi_articles上的isi_lac_authored_articles和({1}}上的(article_id,year)索引(article_id,num_citations)和isi_issues上的偶数(国家/地区)将显着加快查询速度索引适合内存,但是,从另一方面来说,将使索引更大并且稍微减慢了表中的插入。