【问题标题】:mysql like query is very slow in pulling resultsmysql 之类的查询在拉取结果时非常慢
【发布时间】:2018-07-09 11:52:18
【问题描述】:

我有一个非常大的 mysql 数据库,由 35 个表组成。每个表的结构都不同,但都有一些共同的字段。 'entity_name' 是所有表格中的一个常见字段。这是一个VARCHAR 字段。有些表包含数百万条记录,而有些则包含数十亿条记录。

我正在所有这些表中搜索搜索键并提取实体名称,以及包含匹配记录的表中的一些常见字段;将结果推送到数组中,最后以 HTML 格式显示。查询非常简单:

SELECT * FROM table_name WHERE entity_name LIKE '%search_key%' //Partial match.

SELECT * FROM table_name WHERE entity_name LIKE 'search_key%' //Begins with.

SELECT * FROM table_name WHERE entity_name IN('search_key') //Equal to.

通常使用第一个查询。

数据库的大小约为 9GB。搜索过程非常缓慢。根据研究,我发现使用索引可能不起作用,因为我正在搜索:entity_name LIKE '%search_key% 通配符出现在前面。由于我们专注于 varchar 字段,因此分区也不起作用(如果我错了,请更正)。

欢迎任何想法/建议。

【问题讨论】:

  • (1) 如果您的数据库是 9GB,那么没有表有“数十亿”行。 (2) 您可能需要考虑全文索引。
  • 实体名称作为进入数据库的主要方式对我来说不是一个好的选择。我将创建一个带有 entity_id 和 entity_name 的表,其中名称必须是唯一的,然后在所有其他表中使用该 id。但这并不能解决您的速度问题,除非不同名称的数量要少得多,并且在每个表中重复多次。
  • 另一种旧的加快搜索速度的技术是限制需要搜索的内容。这通常是按时完成的。因此,您只能对不到 2 年的数据执行搜索,除非用户特别要求深入了解“存档”结果。
  • @KIKO Software 无法存档记录,搜索必须在完整数据集上进行。

标签: mysql sql sql-like query-performance


【解决方案1】:

当您说LIKE '%search_key' 天生很慢时,您是对的。这种搜索词不是sargable,因为它以% 开头。 entity_name 列上的索引可能仍然会有所帮助,特别是如果您的表有很多列:MySQL 可能能够扫描索引而不是表。但它永远不会很快。

您应该考虑为此应用程序使用 MySQL FULLTEXT searching

【讨论】:

  • 感谢您的反馈,据我所知,如果我是正确的,FULLTEXT 搜索会提取具有单个匹配词的记录?有没有办法将字符串作为一个整体进行匹配?我相信我们不能在其中使用通配符?
  • "我相信我们不能在这使用通配符?" 布尔模式下的 MATCH 子句(搜索全文索引dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html)支持通配符(功能取决于使用的存储引擎)和/或布尔逻辑同时使 LIKE 功能@BijuPDais MATCH(..) AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); 写成... LIKE('%MySQL %') AND ... NOT LIKE('%YourSQL%') 更有用
【解决方案2】:

如果您的 search_key 是动态的(在文本中搜索),最好使用不同类型的数据库。例如弹性或其他类似的东西。

如果您的 search_key 可以定义为 ENUM,请将其放在不同的列中并使用它。

在文本中搜索不是 mySQL 的方式。

【讨论】:

  • 我们的 mysql 数据库在同一个主机上。所以去一个新的数据库可能行不通。你还推荐哪个数据库?
  • 他说 elastic 在 Java 上运行(资源匮乏且速度慢)并且不支持 SQL,因此您需要学习一种新的“语言”.. @BijuPDais .. MongoDB 本来是一个更好的建议仍然是你需要学习一门新的“语言”,但至少不是在 Java 上运行。
【解决方案3】:

如果您在网页中显示您的记录,那么我相信您可能不需要一次性获取全部数据。对于如此庞大的数据,最好的方法是进行分页。

您可以限制查询的记录数,一次可能是 10、25 或 50 条,这可能不会花费太多时间来执行您的查询。您的查询可以是 -

SELECT * FROM table_name WHERE entity_name LIKE '%search_key%' limit x,y;

这里用你的下限替换 x,用你的上限替换 y。

如果您需要匹配记录的计数,请使用以下查询来计算计数。

SELECT count(*) FROM table_name WHERE entity_name LIKE '%search_key%';

希望这会有所帮助!

【讨论】:

  • 这无济于事。如果你使用分页,你必须使用 ORER BY。这样做意味着 MySQL 必须先处理整个表才能限制结果。
  • 恐怕我不能使用分页,因为我显示的结果是查询所有表后获得的。我使用array_merge将结果合并为一个数组,并在页面中迭代并显示这个数组。
  • 分页可能是不可避免的。如果我在 entity_name 'E' 上搜索会发生什么?您将获得如此多的结果,以至于 HTML 输出将以 GB 为单位运行。如果您的数组在此之前没有耗尽内存。
  • 另一种方法是为search_key创建单独的表并通过ID引用它,这将在一定程度上提高速度。否则,使用NoSQL连接存储该表数据,这肯定会完成你的工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
  • 2021-12-09
  • 1970-01-01
相关资源
最近更新 更多