【问题标题】:Optimising a forward index in MySQL在 MySQL 中优化前向索引
【发布时间】:2012-05-10 13:58:06
【问题描述】:

我正在使用 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 上运行。谢谢。

【问题讨论】:

  • @MarcusAdams 是的,但我很乐意改变这一点

标签: mysql sql database query-optimization


【解决方案1】:

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

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

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

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

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

另外,LIMIT 子句中的第一行是 0,所以LIMIT 1, 10 会跳过第一行。使用 LIMIT 0, 10 获取前 10 行。

【讨论】:

  • 感谢您的快速回复,我会处理这些建议。
  • 我添加了一个复合索引并转换为 ansi 连接语法,这有很大帮助。弄清楚如何更改主键需要更长的时间,但我也会这样做。感谢您的帮助。
猜你喜欢
  • 2011-09-03
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多