【问题标题】:How to optimize MySQL table containing 1.6+ million records for LIKE '%abc%' querying如何优化包含 1.6+ 百万条记录的 MySQL 表以进行 LIKE '%abc%' 查询
【发布时间】:2012-07-19 10:38:38
【问题描述】:

我有一个具有这种结构的表,它目前包含大约 160 万条记录。

CREATE TABLE `chatindex` (
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `roomname` varchar(90) COLLATE utf8_bin NOT NULL,
    `username` varchar(60) COLLATE utf8_bin NOT NULL,
    `filecount` int(10) unsigned NOT NULL,
    `connection` int(2) unsigned NOT NULL,
    `primaryip` int(10) unsigned NOT NULL,
    `primaryport` int(2) unsigned NOT NULL,
    `rank` int(1) NOT NULL,
    `hashcode` varchar(12) COLLATE utf8_bin NOT NULL,
    PRIMARY KEY (`timestamp`,`roomname`,`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

roomname 和 username 列都可以包含完全相同的数据,但每个项目的唯一性和重要位来自于将时间戳与这两个项目相结合。

开始需要一段时间(10-20 秒)的查询是这样的:

SELECT timestamp,roomname,username,primaryip,primaryport 
    FROM `chatindex`
    WHERE username LIKE '%partialusername%'

我究竟能做些什么来优化它?我做不到partialusername%,因为对于某些查询,我只会得到实际用户名中心的一小部分,而不是实际值开头的前几个字符。

编辑:

另外,狮身人面像会更适合这个特定目的吗?

【问题讨论】:

  • 如果你需要 "%part%" 那么你必须这样做。您将使用查询结果做什么?你能改变你在非数据库方面的方法吗?

标签: mysql sql optimization


【解决方案1】:

使用 Fulltext indexes ,这些实际上是为此目的而设计的。现在 InnoDb 在 MySQL 5.6.4 中支持全文索引。

【讨论】:

    【解决方案2】:
    1. 在表列用户名上创建索引(全文索引)。
    2. 作为一个想法,您可以在此表上创建一些视图,这些视图将包含根据字母或其他条件过滤的数据,并根据您的代码将决定使用哪个视图来获取搜索结果。

    【讨论】:

      【解决方案3】:

      您应该使用 MyISAM 表进行 Fulltext 搜索,因为它支持 FULLTEXT 索引,MySQL v5.6+ 仍处于开发阶段,您不应将其用作生产服务器,可能需要大约 1 年的时间才能进入 GA。

      现在,您应该将此表转换为 MyISAM 并在 where 子句中添加引用 column 的 FULLTEXT 索引:

      这些链接很有用:

      http://dev.mysql.com/doc/refman/5.0/en/create-index.html

      http://dev.mysql.com/doc/refman/5.1/en/fulltext-fine-tuning.html

      【讨论】:

      • 全文索引相对于普通索引有什么优势。 username 上的任何索引都将阻止全表扫描。这种类型的查询不会使用全文功能。
      【解决方案4】:

      在 MSSQL 上,这是将全文索引与 CONTAIN 子句一起使用的完美案例。 LIKE 子句在这么大的表和要搜索的文本变体这么多的情况下未能获得良好的性能。

      看看这个链接,有很多与dinamic search conditions相关的问题。

      【讨论】:

        【解决方案5】:

        如果您对当前查询进行解释,您将看到您正在对表进行全表扫描,这就是它如此慢的原因。用户名上的索引将大大加快搜索速度,因为索引可以被 MySQL 缓存,并且只有匹配的用户才能访问表行条目。

        全文索引不会实质性地帮助%fred% 等搜索匹配oldfredboy 等,所以我不知道为什么其他人建议使用它。全文索引的作用是创建一个基于单词列表的索引,以便您搜索的列表类似于“解释当前查询”,全文引擎将包含“解释”的行 ID 与包含“当前”的行 ID 和包含“查询”的行 ID 相交" 获取包含所有三个 ID 的列表。添加全文索引会大大增加表的插入、更新删除成本,因此确实会增加性能损失。此外,您需要使用全文特定的“MATCH”语法来充分利用全文索引。

        如果您在“[mysql] fulltext like”上进行问题搜索以查看对此的进一步讨论。

        一个普通的索引会做你需要的一切。像 '%fred%' 这样的搜索需要对索引进行全面扫描,因此您需要尽可能保持索引精简。此外,如果匹配“fred%”的命中率很高,那么首先尝试类似“fred%”的搜索可能也是值得的,因为这将进行索引范围扫描。

        还有一点,你为什么要使用时间戳、房间名、用户名作为主键?这对我来说没有意义。如果您不使用主键作为访问路径,那么 auto_increment id 会更容易。我会认为 房间名称、时间戳、用户名会有些意义,因为您肯定倾向于在时间窗口内访问房间。

        仅添加您将使用的索引。

        【讨论】:

          【解决方案6】:

          表索引(全文索引)对于如此大量的数据是必须的。 如果可能的话,进一步进行表分区。所以这些肯定会提高性能。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-31
            • 1970-01-01
            • 1970-01-01
            • 2018-12-01
            • 2012-05-16
            • 1970-01-01
            相关资源
            最近更新 更多