2

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

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

  • fi_page 是 800k wiki 页面的表
  • 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 万个条目的表格,将关键字链接到 wiki 页面

    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 上运行。谢谢你。

4

1 回答 1

2

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

如果您使用 InnoDB,主键是聚集索引,因此它们要快得多。

即使您不进行此更改,fi_titlekeywordlink 上 ( keyword_id, page_id) 的复合(多列)索引也会提高性能,因为您将在 fi_titlekeywordlink 上有一个覆盖索引(MySQL 不必访问表数据)。这假设您的 MySQL 服务器有足够的 RAM 来容纳内存中的所有索引,并且您已配置 MySQL 服务器以允许它使用足够的 RAM 来做到这一点(配置变量在MyISAMInnoDB之间有所不同)。

有时,隐式 JOIN 可能会变得过于复杂,以至于 MySQL 无法正确优化。您还应该考虑使用JOIN和使用显式 ANSI 标准连接重写查询ON

您可能只是SELECT p.*为了简洁而写,但请确保只选择您需要的列,这样您就不会返回不需要的数据。只返回您需要的列可以减少工作量。

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

于 2012-05-10T14:13:24.797 回答