【问题标题】:mysql query for linked listmysql查询链表
【发布时间】:2013-07-08 22:29:06
【问题描述】:

我正在使用一个实现了单链表(id、parent)的表。这个实现一直运行良好,但最近性能变得难以忍受,因为我的列表越来越长,而且我一直在单独查询节点。

我发现了一篇很有前途的博客,介绍了如何在单个查询中进行查询。 http://explainextended.com/2009/03/25/sorting-lists/

SELECT  @r AS _parent,
        @r := (
        SELECT  id
        FROM    t_list
        WHERE   parent = _parent
        ) AS id
FROM    (
        SELECT  @r := 0
        ) vars,
        t_list

唯一的问题是我对 MySQL 的了解不够,甚至无法使用它。我的问题与我在博客 cmets 上发布的问题相同。如何设置从哪个记录/节点开始?就像我想从示例表中的 id 3 开始一样。它如何知道它何时到达列表末尾并应该停止?我已经尝试过了,它永远运行(可能是由于与前一个问题相关的不当使用)。

谢谢。

【问题讨论】:

  • 能否请您在sqlfiddle.com 上发布您的设置或只是准备一个数据库转储?

标签: mysql sql linked-list


【解决方案1】:

查询通过迭代t_list 表(最后一行)来工作。对于该表中的每一行,SELECT 子句中的子查询重新查询该表,搜索当前行的子行(WHERE parent = _parent -- 但_parent@r 的别名)。在每次迭代中,孩子的id 被分配给@r 变量。

要添加边界,这个变体应该可以解决问题:

SELECT * FROM (
    SELECT
        @r AS _parent,
        @r := (
            SELECT id
            FROM t_list
            WHERE
                ( @c = 0 AND _parent IS NULL AND parent IS NULL ) -- special case if the first item is the root
                OR (parent = _parent)
        ) AS id,
        @c := @c + 1 AS rank
    FROM (
        SELECT @c := 0, @r := parent FROM t_list WHERE id = @start
    ) AS ini,
    (
        SELECT id FROM t_list LIMIT @limit
    ) AS lim
) AS tmp WHERE id IS NOT NULL;

@start@limit 分别替换为第一个项目的id,以及要检索的最大项目数。请test it here


使用 RDBMS 对这样的数据结构进行建模可能完全是个坏主意。为什么不只使用“索引”列?获取列表然后变得即时:

SELECT * FROM list ORDER BY index_column ASC;

也许您的列表应该经常更改,但这样的查询应该相当快,除非列表变得非常大:

-- insert an element at position X 
UPDATE list SET index_column = index_column +1 WHERE index_column > X ORDER BY index_column DESC;
INSERT INTO list VALUE (some_value, X);

-- delete an element at position X 
DELETE FROM list WHERE index_column = X;
UPDATE list SET index_column = index_column -1 WHERE index_column > X ORDER BY index_column ASC;

【讨论】:

  • 我将牢记这一策略,以备将来我拥有的数据库使用。这要简单得多。不幸的是,我无法控制数据库模式,所以我必须让这个链表查询工作。列表的长度通常为 1-3k 节点,并且经常更改。
  • 很高兴为您提供帮助。如果您有空余时间,我很想知道这个查询如何在大型数据集上执行,但范围很短(例如 10 个项目),与 this answer 中建议的简单 JOIN 相比类似的问题。
  • 我对这两种方法都进行了尝试,它们在不到 0.000 秒的时间内返回了 10 个结果。
  • 我认为样本集需要更复杂(SELECT * FROM t_list WHERE id BETWEEN @lower_limit AND @upper_limit)。这意味着您的节点将在表中彼此相对靠近。这不是我的情况。我正在尝试获取它,以便当没有具有当前 id 的 next_id 的记录时,它会停止。
  • @btd 是的,再想一想,我的解决方案似乎根本不起作用。我仍然有偏见地假设id 是连续的。请再次尝试查看我的编辑。这个应该可以的。这是我写过的最丑陋的东西之一,感谢这个机会,很有趣!如果它在您的数据集上运行得很快,请告诉我。
猜你喜欢
  • 2014-03-13
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
相关资源
最近更新 更多