0

标题真的不够解释...

我每小时运行一次查询以准备 MEMORY 表,然后将这些表用于下一小时的一些高强度流量。现在查询看起来像:

INSERT INTO tmp_table
            SELECT DISTINCT SQL_NO_CACHE
            B.*, G.node
            FROM books B
            RIGHT JOIN book_genres G on G.asin=B.asin
            WHERE EXISTS
            (
              SELECT 1 FROM genres K WHERE K.node=G.node
            )
            AND...[nothing special here]

因此,books 表只保存带有 asin 的 PRIMARY KEY 的书籍数据。book_genres 包含 asin 和 node 字段,并包含许多用于站点各个部分的节点。然而,tmp_table 只需要包含流派表中的节点子集,因此是子查询。希望这在不发布完整架构的情况下就足够了。

我们现在想让某些类型相互排斥。这意味着在构建 tmp_table 之后执行此操作:

# Delete records that should have been excluded
DELETE T FROM tmp_table T INNER JOIN 
(
    SELECT N.* FROM tmp_table N INNER JOIN
    (
        SELECT DISTINCT ASIN FROM tmp_table 
        INNER JOIN genres ON genres.node=tmp_table.node
        WHERE isFiction=1
    ) F 
    ON F.asin=N.asin 
    INNER JOIN genres ON  genres.node=N.node
    WHERE genres.isNonFiction=1 
) D 
USING (asin, node)
WHERE D.asin=T.asin AND D.node=T.node

因此,如果该 asin 属于 isFiction=1 的流派,则将删除所有 nonFiction=1 的流派。

但这感觉很难看:使用查询添加数据,然后再次删除它。有什么方法可以将其组合成一个查询以避免双重传递。或者我只是在为自己工作,考虑到(经过一些调整和编辑)上面的工作确实很快就可以接受。

任何想法将不胜感激,谢谢。

添加示例:

books table:
asin        title       price     etc...
B111111111  Book1       $0.99     ....
B222222222  Book2       $0.99     ....
B333333333  Book2       $0.99     ....

book_genres table:
asin        node
B111111111  1111
B111111111  2222
B111111111  3333
B111111111  5555
B222222222  1111
B222222222  3333
B222222222  4444
B333333333  1111
B333333333  2222

genres table:
node    name         isFiction    isNonFiction
1111    Bestsellers  0            0
2222    Romance      1            0
3333    Biographies  0            1
4444    History      0            1

因此,在 INSERT INTO 运行后,tmp_table 将如下所示:

asin       title       node 
B11111111  Book1       1111
B11111111  Book1       2222
B11111111  Book1       3333
B22222222  Book2       1111
B22222222  Book2       3333
B22222222  Book2       4444
B33333333  Book3       1111
B33333333  Book3       2222

Book1 没有节点 5555 的记录,因为它不在流派表中,我们在 tmp_table 中不需要它。其他所有内容几乎都是数据的反规范化,因为 WHERE 可以识别数据库中数百万本书中的一小部分,这可以更快地使用。

下一步确保如果一本书有 isFiction 节点,则删除该书的所有 isNonFiction 节点。

运行 DELETE 后,tmp_table 中的最终结果为:

asin       title       node 
B11111111  Book1       1111
B11111111  Book1       2222
B22222222  Book2       1111
B22222222  Book2       3333
B22222222  Book2       4444
B33333333  Book3       1111
B33333333  Book3       2222

唯一的区别是 Book1 的节点 3333 已被删除,因为 Book1 位于 isFiction=1 的 2222 节点中,而节点 3333 的 isNonFiction=1。Book2 没有改变,因为它不包含 isFiction 节点。同样,Book3 未更改,因为它不包含 isNonFiction 节点。

在这个阶段,它正在使用这个实现,尽管运行时间从大约 20 多秒增加到大约 40 秒。这并不奇怪,因为 DELETE 有点令人费解。这可能是一个足够体面的解决方案,但如果其他人有一个想法可以让整个事情变得更简单或更快,我会很高兴。

标记...

4

1 回答 1

0

它很丑陋。它工作正常,直到数据库上有任何其他重大负载,然后一切都非常缓慢。这主要是由于服务器的 IO 限制,但更简单的方法是将 isfiction 和 isNonFiction 放入 MEMORY 表中,然后 DELETE 语句可以如下所示:

    DELETE tmp_table FROM tmp_table
         INNER JOIN
         (
            SELECT ASIN, MAX( isFiction ) AS isFiction, MAX( isNonFiction ) AS isNonFiction
            FROM tmp_table
            GROUP BY ASIN
            HAVING isFiction =1
            AND isNonFiction =1
         ) D
         WHERE D.ASIN=tmp_table.ASIN AND tmp_table.isNonFiction=1

在测试中,这将整个过程从大约 90 秒缩短到 10 秒。

于 2013-08-13T07:40:20.887 回答