在数百万行上进行10亿次查询的最快方法

时间:2018-01-15 16:54:25

标签: php mysql full-text-search amazon-rds

我正在运行一个PHP脚本,该脚本使用包含数百万行的表搜索相对较大的MySQL实例,以在列description中找到类似“糖尿病”的术语,该列具有全文索引。但是,有一天我只通过几百个查询,所以看起来我的方法永远不会起作用。 description列中的条目平均长度为1000个字符。

我正在试图找出我的下一步行动,我有几个问题:

  1. 我的MySQL表中有不必要的列,没有被查询。会删除那些会影响性能吗?

  2. 我假设在本地运行而不是在RDS上运行会大大提高性能吗?我有一个不错的macbook,但我选择了RDS,因为成本不是问题,我试图在比我的Macbook更好的实例上运行。

  3. 使用像Go而不是PHP这样的编译语言会比测试示例中的5-10x提升人报告更多吗?也就是说,鉴于我的任务是否有理由认为静态语言会产生100倍或更高的速度提升?

  4. 我应该将数据放在文本或CSV文件而不是MySQL中吗?使用MySQL只会造成不必要的开销吗?

  5. 这是查询:

    SELECT id 
    FROM text_table 
    WHERE match(description) against("+diabetes +mellitus" IN BOOLEAN MODE);
    

    这是查询的EXPLAIN输出行,显示优化器正在使用FULLTEXT索引:

    1   SIMPLE  text_table  fulltext    idx idx 0   NULL    1   Using where
    

    RDS实例是 db.m4.10xlarge ,它有160GB的RAM。 InnoDB缓冲池通常约占RDS实例RAM的75%,这使其达到120GB。

    text_table状态为:

               Name: text_table
             Engine: InnoDB
            Version: 10
         Row_format: Compact
               Rows: 26000630
     Avg_row_length: 2118
        Data_length: 55079485440
    Max_data_length: 0
       Index_length: 247808
          Data_free: 6291456
     Auto_increment: 29328‌​568
        Create_time: 2018-01-12 00:49:44
        Update_time: NULL
         Check_time: NULL
          Collation: utf8_general_ci
           Checksum: NULL
     Create_options: 
            Comment: 
    

    这表明该表有大约2600万行,数据和索引的大小为51.3GB,但这不包括FT索引。

    对于FT索引的大小,请查询:

    SELECT stat_value * @@innodb_page_size 
    FROM mysql.innodb_index_stats 
    WHERE table_name='text_table' 
    AND index_name = 'FTS_DOC_ID_INDEX' 
    AND stat_name='size'
    

    FT索引的大小为480247808

1 个答案:

答案 0 :(得分:2)

跟进上面关于并发查询的评论。

如果查询需要30秒才能执行,那么您用于客户端应用程序的编程语言就不会有任何区别。

我有点怀疑查询实际需要1到30秒才能执行。我测试了MySQL全文搜索,我发现即使在我的笔记本电脑上也能在1秒内完成搜索。请参阅我的演示文稿https://www.slideshare.net/billkarwin/practical-full-text-search-with-my-sql

这可能不是查询花了这么长时间,但它是您提交的提交查询的代码。你的代码还在做什么?

您如何衡量查询效果?你在使用MySQL的查询分析器吗?请参阅https://dev.mysql.com/doc/refman/5.7/en/show-profile.html这将有助于隔离MySQL执行查询所需的时间,因此您可以比较其余PHP代码运行所需的时间。

使用PHP将是单线程的,因此您一次串行运行一个查询。您使用的RDS实例有40个CPU内核,因此您应该能够一次执行多个并发查询。但每个查询都需要由自己的客户端运行。

因此,一个想法是将输入搜索项分成至少40个子集,并针对每个相应的子集运行PHP搜索代码。 MySQL应该能够很好地运行并发查询。也许会有轻微的开销,但这将通过并行执行得到补偿。

您可以手动将搜索词拆分为单独的文件,然后以每个相应的文件作为输入运行PHP脚本。这将是解决这个问题的直接方法。

但要真正专业,请学会使用像GNU parallel这样的工具来运行40个并发进程,并自动将这些进程分开。