MySQL - 选择列与任何链接列表中的条目匹配的行

时间:2014-08-21 21:11:47

标签: mysql sql database query-optimization

为慢速搜索引擎获取许多客户投诉 - 这是理所当然的。

我有一个数据库搜索引擎,我对如何进行搜索的最后一部分感到有些困惑,我需要以良好的性能运行。如果用户搜索某些单词,则最多可能需要一分钟才能执行。

解释我的设置;我有一个名为 my_table 的表格,带有可搜索的项目条目。这些项目有一个名为 linked_list 的列,其中包含指向表 linked_list id (主要索引)的指针。

linked_list id

my_table 中的行可以指向 linked_list 中的任何 id ,以及特定列表中的任何位置。 (没有列表超过7个链接深)

我需要允许用户搜索 linked_list 中的。所以我目前这样做的方法是首先搜索用户查询的 linked_list ,如下所示:

SELECT id FROM linked_list WHERE value LIKE '%query%'

在我得到所有结果后,我将它们变成了一个带有php的 id 数组,如下所示:{2516,8645,235,4,665,...}

然后我将这些数组项中的每一个都给它自己的" WHERE .. IN .."如下所示,并将它们组合在一起。

您可以想象,如果我在 linked_list 中有超过4个匹配,则搜索会变得不合理。

SELECT * FROM my_table
WHERE 
    (((1108 in (linked_list_id,
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = linked_list_id), 
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent )))) 
OR ((2791 in (linked_list_id,
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = linked_list_id), 
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent )))) 
....

在你告诉我之前,只需将整个链表存储在my_table"中,这是不合理的。 linked_list可能会改变,它将成为维护的噩梦。

我已经考虑过使用Union,Join,HAVING .. IN ..但是没有任何工作。我会感激任何可以帮助我解决这个问题的人!谢谢!

---编辑--- 这是一些示例数据。

MY_TABLE

  id  |  linked_list_id
--------------------
   1  |    1000
   2  |    1050
   3  |    1234
   4  |    1001
   5  |    1000
   6  |    1600

linked_list

  id  |  parent   |   value   |
--------------------------------
1000  |     0     |     A     |     (This is the root of one linked list)
1001  |    1000   |     B     |
1050  |    1600   |     C     |
1234  |     0     |     D     |     (This is the root of another linked list)
1500  |    1000   |     E     |
1600  |    1001   |     AA    |

(所以这个数据的结构是:)

1050 -> 1600 -> 1001 -> 1000 -> 0
                1500 ---^       |
                        1234 ---^

注意:我拥有的最长链表是7个节点深。这受到应用程序的限制,因此他们很可能不会超过7个节点。

所以,如果我搜索

SELECT id FROM linked_list WHERE value LIKE '%A%'

我得到了

{1000,1600}

然后当我运行长查询时,它看起来像这样:

SELECT id FROM my_table
WHERE 
    (((1000 in (linked_list_id,
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = linked_list_id), 
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent )))) 
OR ((1600 in (linked_list_id,
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = linked_list_id), 
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent ),
    (SELECT @last_parent:=`parent` FROM `linked_list` WHERE `id` = @last_parent )))) 
....

我希望返回的结果是

{1,2,4,5,6}

因为这些行中的每一行都在其链接列表中的某处包含%A%。

希望这有帮助。

1 个答案:

答案 0 :(得分:1)

所以我自己解决了这个问题。

对于这可能有所帮助的人,我做了以下事情。

1)我首先查询 linked_list 以查找%query%的任何匹配项,并将结果写入ID数组,如(1,2,3,4)

2)我递归查询 linked_list 以获取其父项在上面的ID数组中的所有CHILDREN,并将结果附加到ID数组。

3)然后在我的主 my_table 搜索查询中,我只是说

'... HAVING `linked_list_id` IN (1,2,3,4,5,6,7,...)'