优化MySQL中的前向索引

时间:2012-05-10 13:58:07

标签: mysql sql database query-optimization

我正在使用MySQL在wiki上构建转发索引。我遇到了查询的性能问题,我希望能够帮助优化我的架构或查询

数据库大约1GB,有三个表

  • fi_page是800k维基页面的表格
  • fi_keyword是一个包含70k关键字的表格

    CREATE TABLE `fi_keyword` (  
      `id` int(11) NOT NULL AUTO_INCREMENT,  
      `keyword` varchar(100) NOT NULL,  
      PRIMARY KEY (`id`),  
      UNIQUE KEY `keyword` (`keyword`)  
    );
    
  • fi_titlekeywordlink是一个包含600万个条目,将关键字链接到维基页面的表格

    CREATE TABLE `fi_titlekeywordlink` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `keyword_id` int(11) NOT NULL,
      `page_id` int(11) NOT NULL,
      PRIMARY KEY (`id`),
      KEY `fi_titlekeywordlink_a6434082` (`keyword_id`),
      KEY `fi_titlekeywordlink_c2d3d2bb` (`page_id`),
      CONSTRAINT `keyword_id_refs_id_67197756` FOREIGN KEY (`keyword_id`) REFERENCES `fi_keyword` (`id`),
      CONSTRAINT `paper_id_refs_id_705ddf03` FOREIGN KEY (`page_id`) REFERENCES `fi_page` (`id`)
    );
    

我正在将“搜索术语丰富”的搜索转换为SQL查询,例如

    select p.*
      from
        fi_keyword as k0, fi_titlekeywordlink as l0,
        fi_keyword as k1, fi_titlekeywordlink as l1,
        fi_keyword as k2, fi_titlekeywordlink as l2,
        fi_keyword as k3, fi_titlekeywordlink as l3,
        fi_page as p
      where
        k0.keyword = e and k0.id = l0.keyword_id and p.id = l0.paper_id
        and k1.keyword = 'search' and k1.id = l1.keyword_id and p.id = l1.paper_id
        and k2.keyword = 'terms' and k2.id = l2.keyword_id and p.id = l2.paper_id
        and k3.keyword = 'galore' and k3.id = l3.keyword_id and p.id = l3.paper_id
      limit 1,10
然而,这需要大约半秒才能在我的MBP上运行。您是否有任何关于如何通过更改架构或查询来加速此类操作的建议?在这种情况下我不能使用单独的搜索服务器,正向索引必须在MySQL上运行。谢谢。

1 个答案:

答案 0 :(得分:2)

以插入性能为代价,您可以从两个表中删除代理id主键列,并在keyword列上为fi_keyword和(keyword_id创建主键索引, page_id)作为fi_titlekeywordlink的主键索引。

如果您使用InnoDB,主键是聚簇索引,因此速度更快。

即使您没有进行此更改,fi_titlekeywordlink上的复合(多列)索引(keyword_idpage_id)也会提高效果,因为您将拥有覆盖索引( MySQL不必访问fi_titlekeywordlink上的表数据。这假设您的MySQL服务器有足够的RAM来容纳内存中的所有索引,并且您已经配置了MySQL服务器以允许它使用足够的RAM来实现它(配置变量在MyISAM和{{3之间不同}})。

有时,隐式JOIN对于MySQL来说可能过于复杂而无法正确优化。您还应该考虑使用JOINON使用显式ANSI标准连接重写查询。

为简洁起见,您可能只是编写了SELECT p.*,但请务必仅选择所需的列,以便您不会返回不需要的数据。只返回您需要的列可以减少工作量。

此外,LIMIT子句中的第一行为0,因此LIMIT 1, 10会跳过第一行。使用LIMIT 0, 10获取前10行。