15

我正在尝试为网站编写搜索功能,并且我决定使用 MySQL 临时表来处理数据输入,通过以下查询:

CREATE TEMPORARY TABLE `patternmatch`
  (`pattern` VARCHAR(".strlen($queryLengthHere)."))

INSERT INTO `patternmatch` VALUES ".$someValues

$someValues带有布局的一组数据在哪里('some', 'search', 'query')- 或者基本上是用户搜索的内容。images然后我根据表中的数据搜索我的主表,patternmatch如下所示:

SELECT images.* FROM images JOIN patternmatch ON (images.name LIKE patternmatch.pattern)

然后,我根据每个结果与输入的匹配程度应用启发式或评分系统,并通过该启发式等显示结果。

我想知道创建临时表需要多少开销?我知道它们只存在于会话中,并且在会话结束后立即被丢弃,但是如果我每秒有数十万次搜索,我可能会遇到什么样的性能问题?有没有更好的方法来实现搜索功能?

4

3 回答 3

6

您所说的完全正确,临时表仅对当前用户/连接可见。尽管如此,仍然存在一些开销和其他一些问题,例如:

  • 对于您将要创建并填充该表(并稍后删除)的数千个搜索中的每一个 - 不是每个用户,每个搜索。因为每次搜索很可能会重新执行脚本,并且“每个会话”并不意味着 PHP 会话——它意味着数据库会话(打开连接)。
  • 您将需要您可能没有的CREATE TEMPORARY TABLES特权。
  • 尽管如此,该表确实应该具有 MEMORY 类型,它比看起来更能窃取您的 RAM。因为即使有 VARCHAR,MEMORY 表也使用固定长度的行存储。
  • 如果您的启发式方法稍后需要引用该表两次(如SELECT xyz FROM patternmatch AS pm1, patternmatch AS pm2 ...) - 这对于 MEMORY 表是不可能的。

接下来,对您和数据库而言,将其LIKE '%xyz%'直接添加到您的imagesWHERE子句会更容易。它将做同样的事情,而无需创建 TEMP TABLE 并加入它。

在任何情况下 - 无论你走哪条路 - WHERE 都会非常缓慢。即使您添加了一个索引,images.name您也很可能需要LIKE '%xyz%'代替 LIKE 'xyz%',因此该索引不会被使用。

我在问一个特定于会话的临时表来处理用户的搜索输入(在搜索时创建,在会话结束时删除)是否是处理搜索功能的适当方式。

不。 :)

替代选择

MySQL 有一个内置的全文搜索(从 5.6 开始也适用于 InnoDB),它甚至可以为您提供评分:我强烈建议您阅读并尝试一下。您可以确定数据库比您更了解如何有效地进行搜索。

如果您打算使用 MyISAM 而不是 InnoDB,请注意经常被忽视的限制,即 FULLTEXT 搜索仅在结果数少于表总行数的 50% 时才返回任何内容。

您可能想要查看的其他内容例如 Solr(对该主题本身的很好的介绍将是http://en.wikipedia.org/wiki/Apache_Solr的开头)。我们在公司中使用它,它做得很好,但它需要相当多的学习。

概括

当前问题本身(搜索)的解决方案是使用 FULLTEXT 功能。

如果我每秒有数十万次搜索,我可能会遇到什么样的性能问题?有没有更好的方法来实现搜索功能?

给你一个数字,每秒 10.000 次调用已经不是“微不足道的”——每秒数十万次搜索,你会遇到的那种性能问题在你的设置中无处不在。您将需要几台服务器、负载平衡和大量其他令人惊叹的技术垃圾。其中之一将是例如 Solr ;)

于 2013-09-24T18:56:20.337 回答
2
  1. 在磁盘上创建临时表相对昂贵。在您的情况下,听起来它会比它的价值慢。
  2. 通常只值得在内存中创建临时表。但是您需要知道您始终有足够的可用内存。如果您计划每秒支持如此多的搜索,这不是一个好的解决方案。
  3. MySQL内置了全文搜索功能。它适用于小型系统。这可能会比您的临时表和 JOIN 执行得更好。但是,如果您想支持每秒数千次搜索,我不推荐它。它可能会消耗过多的整体数据库性能。另外,您随后被迫使用 MyISAM 进行存储,这在您的场景中可能有其自身的问题。
  4. 对于如此多的搜索,您需要将工作转移到另一个系统。已经存在大量带有评分的搜索系统。看看 ElasticSearch、Solr/Lucene、Redis 等。
于 2013-09-23T21:58:46.753 回答
1

从您提供的代码来看,我真的认为不需要 tmp 表,也不需要 FULLTEXT 搜索。但是...关于 tmp 表性能:

tmp 表的创建/清理不会写入事务日志,因此操作系统会相对较快地完成所涉及的 I/O。如果临时表很小且寿命很短,并且您有很多可供操作系统使用的缓冲区,那么实际上甚至不会触及磁盘。如果您认为无论如何,请获得 SSD 驱动器,并获得更多 RAM。

但是,如果您对每秒查看数十万次搜索是现实的,那么您手头就有一个大型工程项目。为什么不这样做:

select images.* from images where name in ('some', 'search', 'query')

?

于 2013-09-28T04:33:48.027 回答