【问题标题】:Smart and fast way to store a lot of text data in MySQL在 MySQL 中存储大量文本数据的智能快速方法
【发布时间】:2021-05-17 02:56:59
【问题描述】:

我在处理一个包含许多记录的大表时遇到了一个问题(顺便说一下 MySQL)。

我有两种情况。第一个是具有主键和 18 个不同 varchar 字段的单个表。

id Field1 Field2 Field18
1 abc abc abc
2 def def def
100 xyz xyz xyz

第二种情况是我有一个表格,它以不同的方式组织所有信息:

id_record field_name value
1 field1 abc
1 field2 abc
1 field3 abc
2 field1 def
100 field18 xyz

首先我有一个固定的结构(没有灵活性)并且可能有很多空格。在第二种解决方案中,我可以轻松添加新字段,但表格会快速增长。

在一些测试中,我运行的两个测试都存储了大约 200 000 条记录。但随着我的成长(我用 500 000 和 1M 进行测试),在第二种情况下事情变得缓慢。

第二个 id_record 和 field_name 是索引,值是全文。但这并没有太大帮助。

当我尝试合并两个匹配项时,事情变得特别慢:

select f1.id_record from table f1 where f1.field = 'field1' and f1.value like '%abc%' and f1.id_record in (
    select f2.id_record from table f2 where f2.field = 'field18' and f2.value like '%abc%'
);

select f1.id_record from table f1, table f2 where f1.field = 'field1' and f2.field = 'field18' and f1.id_record = f2.id_record and f1.value like '%abc%' and f2.value like '%abc%';

关于如何在第二种情况下表现更好的任何想法?或者对于如何更好地构建此类数据有什么新想法?

【问题讨论】:

  • 如果您熟悉python,那么我强烈建议您将mysql-connecter与python一起使用。您可以编写一个脚本,将任何类型的文件作为输入并将该数据存储到 MySQL 中。
  • 您创建了哪些索引?第二种情况是可怕的交叉连接,所以它可能不是你想要的。
  • 我正在使用 PHP,所以它不起作用。我为 id_record 和 field 列使用单独的索引,为 value 列使用全文
  • 您的典型查询是否在某些列中查找子字符串?这些子字符串是“单词”吗?
  • 我可能会搜索全文或只是其中的一部分,并且文本是一个句子(我很少会存储全文,但可能偶尔会发生一次)。这实际上不是我主要关心的问题。这是性能与灵活性。如果我使用传统表格,我需要设置的列数量有限。所以我最终可能会得到很多空值或用完插槽。使用第二种方法我有更大的灵活性,我只存储有效数据(不需要存储空值),但我很快就会增长该表并且性能开始下降。

标签: mysql sql


【解决方案1】:

如果您正好有 18 列并且不需要添加更多,那么第一种是一种非常合理的存储数据的方式。您想要的查询很简单:

select t.*
from t
where t.field like '%abc%' and t.field2 like '%abc%';

不幸的是,此查询需要全表扫描(因为like 中的通配符)。如果不使用全文索引,除非数据非常稀疏,否则这可能是您能做的最好的事情。

第二种结构为上述查询提供了两种可能性。一个使用JOIN

select f1.id_record
from table f1 join
     table f2 
     on f1.id_record = f2.id_record
where f1.field = 'field1' and f2.field = 'field18' and
      f1.value like '%abc%' and f2.value like '%abc%';

最好的索引是(id_record, field, value)。如果field1field18 非常稀疏,这可能会有不错的性能。

我通常推荐group by,对于这种类型的查询:

select f.id_record
from table f
where (f.field = 'field1' and f.value like '%abc%') and
      (f.field = 'field18' and f.value like '%abc%')
group by f.id_record
having count(*) = 2;

但是,我推荐 group by 是因为它的灵活性,而不是特别是因为它的性能。

【讨论】:

  • 18 不是一个具体的数字,也许我在第一个问题上忘了提到这一点。我的意思是,我在场景 1 中有特定的文本列,我担心它对于某些情况可能还不够。这就是为什么我遇到了场景 2,这种方式会更加灵活,但随着记录数量的增长会变慢。
  • @racquad - 是的,EAV 更“灵活”……而且速度慢……而且笨拙。
  • @RickJames 还有其他选择吗?还是第一种方法更好?
  • @racquad - 向我们展示FULLTEXT 版本。
猜你喜欢
  • 1970-01-01
  • 2010-11-11
  • 2014-03-03
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 1970-01-01
  • 2018-09-21
相关资源
最近更新 更多