我有一个非常简单的模式表:
CREATE TABLE q(
orig INTEGER NOT NULL,
dest INTEGER NOT NULL,
cost FLOAT,
PRIMARY KEY (orig, dest)
);
我需要以最小化成本的方式向后走这张桌子。让我解释一下。
我需要15点的巡视,点数可以是orig
或dest
。我的算法是从最后dest
到最初orig
的回溯。所以这就是我拼写出来的方式:
鉴于最终
dest
,请找到orig
,该dest
将链接到所述cost
,且orig
最少。相应的dest
成为新的dest
;循环这15次。
我们假设我知道最后10
是数字orig
。允许我以dest
最小化方式找到导致cost-
的{{1}}的SQL语句是:
SELECT orig FROM q WHERE cost = (SELECT MIN(cost) FROM q WHERE dest = 10);
现在我将使用上面函数返回的orig
来查找前一个点(假设它已返回,比如指向5
):
SELECT orig FROM q WHERE cost = (SELECT MIN(cost) FROM q WHERE dest = 5);
我可以这样继续,直到得到15分。
如何在SQL中进行有效的查询?我的桌子有5000万行。
答案 0 :(得分:0)
这是一个假设您正在使用SQL Server 2005+的查询。它使用公用表表达式(CTE)。此示例实际上返回具有所选orig和dest的具有累积成本的所有路径。它还显示路径中的点数。它可以被改变以返回最佳选择(例如,最低成本,最少步骤等)。
我不知道表现如何。但是,索引会有所帮助。
WITH Paths AS -- Get list of all paths
( SELECT ROW_NUMBER() OVER (ORDER BY orig) AS PathNumber, orig,
dest, cost, 1 AS points
FROM q
UNION ALL
SELECT Paths.PathNumber, Paths.orig,
q.dest, q.cost, paths.points + 1 AS points
FROM Paths
JOIN q ON Paths.dest = q.orig
WHERE Paths.points < 15
)
, PathsRows AS -- Get total points in each path
( SELECT COUNT(*) OVER (PARTITION BY PathNumber) AS TotalPoints, PathNumber
, orig, dest, cost, points
FROM Paths
)
, PathsSum AS -- summarize for each path
( SELECT PathNumber,
MIN(CASE WHEN points = TotalPoints THEN orig END) AS orig,
MAX(CASE WHEN points = TotalPoints THEN dest END) AS dest,
SUM(cost) AS cost, MAX(points) AS points
FROM PathsRows
GROUP BY PathNumber
)
SELECT PathNumber, orig, dest, cost, points
FROM PathsSum
WHERE dest = 4
and orig = 1
ORDER BY PathNumber, points
答案 1 :(得分:0)
简短回答:你不能。
更长的答案:假设我已经正确理解了你的问题,你可以编写一个尽可能高效的SQL语句,但是在一个合理的时间范围内返回结果是非常不可能的 - 比如,宇宙的年龄如此远。
假设您的5000万行表没有重复,并将直接路径从所有位置映射到所有其他位置,那么所包含的位置数大约是5000万的平方根 - 即。有点超过7070个地点。
因此可以采用的路径数量为7070 x 7069 x 7068 ... x 7056,或换句话说,大于7000 ^ 15(约4.75 x 10 ^ 57)。
最终,这是Travelling Salesman Problem的变体 - 基于SQL的暴力方法完全不适合解析它,数据集很大。