我有一个包含URL字符串的表,即
/A/B/C
/C/E
/C/B/A/R
每个字符串都分为标记,在我的情况下,分隔符为'/'。然后我为每个标记分配整数值,并将它们放入字典(不同的数据库表),即
A : 1
B : 2
C : 3
E : 4
D : 5
G : 6
R : 7
我的问题是在第一个表中找到包含给定令牌序列的那些行。另外一个问题是我的输入是整数序列,即我有
3, 2
我想找到以下行
/A/B/C
/C/B/A/R
如何以有效的方式做到这一点。我的意思是如何设计合适的数据库结构。
我使用PostgreSQL,解决方案应该适用于第一个表中的2百万行。
为了澄清我的例子 - 我需要'B'和'C'都在URL中。 “B”和“C”也可以在URL中以任何顺序出现。
我需要高效的SELECT。 INSERT不一定非常有效。如果这会改变任何内容,我不必在SQL中完成所有工作。
提前致谢
答案 0 :(得分:1)
我不知道该怎么做,但我只是给你一些可能有用的想法。你已经有了初始表。您处理并创建令牌表:
+------------+---------+
| TokenValue | TokenId |
+------------+---------+
| A | 1 |
| B | 2 |
| C | 3 |
| E | 4 |
| D | 5 |
| G | 6 |
| R | 7 |
+------------+---------+
这对我没问题。现在,我要做的是创建一个新表,在其中我将原始表与令牌表(OrderedTokens
)的标记相匹配。类似的东西:
+-------+---------+---------+
| UrlID | TokenId | AnOrder |
+-------+---------+---------+
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 3 |
| 2 | 5 | 1 |
| 2 | 2 | 2 |
| 2 | 1 | 3 |
| 2 | 7 | 4 |
| 3 | 3 | 1 |
| 3 | 4 | 2 |
+-------+---------+---------+
这样,只要您使用订单字段,您甚至可以重新创建原始表格。例如:
select string_agg(t.tokenValue, '/' order by ot.anOrder) as OriginalUrl
from OrderedTokens as ot
join tokens t on t.tokenId = ot.tokenId
group by ot.urlId
上一个查询将导致:
+-------------+
| OriginalUrl |
+-------------+
| A/B/C |
| D/B/A/R |
| C/E |
+-------------+
所以,你甚至不需要原来的桌子了。如果您想获得具有任何提供的令牌ID的Url(在本例中为B
或C
),您可以使用此:
select string_agg(t.tokenValue, '/' order by ot.anOrder) as OriginalUrl
from OrderedTokens as ot
join Tokens t on t.tokenId = ot.tokenId
group by urlid
having count(case when ot.tokenId in (2, 3) then 1 end) > 0
这导致:
+-------------+
| OriginalUrl |
+-------------+
| A/B/C | => It has both B and C
| D/B/A/R | => It has only B
| C/E | => It has only C
+-------------+
现在,如果你想获得所有有两个ID的Url,那么试试这个:
select string_agg(t.tokenValue, '/' order by ot.anOrder) as OriginalUrl
from OrderedTokens as ot
join Tokens t on t.tokenId = ot.tokenId
group by urlid
having count(distinct case when ot.tokenId in (2, 3) then ot.tokenId end) = 2
在count
中添加要过滤的所有ID,然后等于计算您添加的ID数量。上一个查询将导致:
+-------------+
| OriginalUrl |
+-------------+
| A/B/C | => It has both B and C
+-------------+
有趣的是,我提供的解决方案都没有产生预期的结果。那么,我是否误解了您的要求,或者您提供的预期结果是错误的?
如果这是正确的,请告诉我。
答案 1 :(得分:0)
这实际上取决于你的效率是什么意思。这将是查询性能和存储之间的权衡。
如果您想有效地存储此信息,那么您当前的方法是合适的。您可以通过执行以下操作来查询数据:
SELECT DISTINCT
u.url
FROM
urls u
INNER JOIN
dictionary d
ON
d.id IN (3, 2)
AND u.url ~ E'\\m' || d.url_component || E'\\m'
此查询将花费一些时间,因为需要执行全表扫描,并对每个URL执行正则表达式逻辑。但是,插入和存储数据非常容易。
但是,如果要优化查询性能,可以创建URL组件的引用表;它看起来像这样:
/A/B/C A
/A/B/C B
/A/B/C C
/C/E C
/C/E E
/D/B/A/R D
/D/B/A/R B
/D/B/A/R A
/D/B/A/R R
然后,您可以在此表上的URL组件上创建聚簇索引。此查询可以非常快速地检索您的结果:
SELECT DISTINCT
u.full_url
FROM
url_components u
INNER JOIN
dictionary d
ON
d.id IN (3, 2)
AND u.url_component = d.url_component
基本上,这种方法可以预先提高查询的复杂性。如果您正在进行少量插入,但对此数据进行了大量查询,那么这是合适的。
创建此URL组件表非常简单,具体取决于您可以使用的工具。一个简单的awk脚本可以在一两分钟内完成2M记录,随后的副本也可以快速复制到数据库中。如果您需要支持此表的实时更新,我建议使用非SQL解决方案:无论您的应用程序编码在何处,都可以使用正则表达式来解析URL并将组件插入到组件表中。如果您仅限于使用数据库,那么插入触发器可以实现相同的角色,但这将是一种更脆弱的方法。