1

我有一个文章的主表,它通过连接表信息链接到只有少量条目的表标签。我想拆分 Articles 表,方法是删除行或创建一个仅包含我想要的条目的新表,基于缺少指向某个标签的链接。有几百万篇文章。我怎样才能做到这一点?

并不是所有的文章都有任何标签,有些文章有很多标签。

例子:

table Articles
  primary_key id
table Info
  foreign_key article_id
  foreign_key tag_id
table Tags
  primary_key id

对我来说,一开始就很容易分离出匹配的文章,所以我想也许我可以这样做,然后使用 NOT IN 语句,但运行速度太慢,不清楚它是否会完成。我用这些命令做到了:

INSERT INTO matched_articles SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5;
INSERT INTO unmatched_articles SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m);

如果它有所作为,我在 Postgres 上。

4

3 回答 3

1

您的查询看起来不错,除了第一个应该是内连接,而不是左连接。如果您想尝试其他方法,请考虑以下几点:

INSERT INTO matched_articles 
SELECT * 
FROM articles a 
INNER JOIN info i ON a.id = i.article_id 
WHERE i.tag_id = 5;

INSERT INTO unmatched_articles 
SELECT * 
FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND a.id <> 5
WHERE a.id IS NULL

这可能会更快,但实际上,如果您只需要执行一次,您所拥有的可能就可以了。

于 2010-03-20T18:17:12.000 回答
1
INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

INSERT INTO unmatched_articles 
SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m); 

这里有很多错误,我不知道从哪里开始。好的,在您的第一次插入中,您不需要左连接,实际上您实际上没有左连接。它应该是

INSERT INTO matched_articles 
SELECT * FROM articles a INNER JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

如果您需要左连接,您将拥有

INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5; 

当您将左连接右侧的某些内容放入 where 子句(而不是搜索空值)时,您将其转换为内连接,因为它必须满足该条件,因此没有右表中的匹配项被消除。

现在第二个语句可以用左连接的特殊情况来完成,尽管你所拥有的会起作用。

INSERT INTO matched_articles 
SELECT * FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5
WHERE i.tag_id is null

这将为您提供 info 表中的所有记录,但与 article 表匹配的记录除外。

接下来,您不应该在未指定要插入的字段的情况下编写插入语句。您也不应该使用 select * 编写选择语句,尤其是在您有联接的情况下。这通常是草率、懒惰的编码,应该修复。如果有人更改了其中一张表的结构但未更改另一张表的结构怎么办?这种事情不利于维护,对于带有连接的 select 语句,它会返回一个列两次(连接列),这是对服务器和网络资源的浪费。懒得指定你需要什么并且只指定你需要什么只是糟糕的编码。所以要改掉这个习惯,不要再为任何生产代码这样做了。

如果您当前的状态太慢,您也可以使用正确的索引来修复它。id 字段是否在两个表上都有索引?另一方面,如果有数百万篇文章,插入它们需要时间。通常最好一次分批进行 50000 个(如果这需要太长时间,则更少)。只需执行插入循环,选择顶部 XXX 记录,然后循环直到受影响的行数为零。

于 2010-03-20T18:21:51.850 回答
1

不确定 Postgres 是否有临时表的概念。
这也是如何做到的。

CREATE Table #temp
AS SELECT A.ID, COUNT(i.*) AS Total
FROM Articles A
LEFT JOIN info i
ON A.id = i.Article_ID AND i.Tag_ID = 5
GROUP BY A.ID

INSERT INTO Matched_Articles
SELECT A.*
FROM Articles A INNER JOIN #temp t
ON A.ID = t.Article_ID AND T.Total = 0

DELETE FROM #Temp
WHERE Total = 0

INSERT INTO UnMatched_Articles
SELECT A.*
FROM Articles AINNER JOIN #temp t
ON A.ID = t.Article_ID

请注意,我没有使用任何编辑器来尝试这个。
我希望这能给你提示我将如何处理这个问题。

于 2010-03-20T18:26:57.753 回答