【问题标题】:most optimized way to select "flagged posts" using where & limit in mysql database使用 mysql 数据库中的 where 和 limit 选择“标记的帖子”的最优化方法
【发布时间】:2010-11-06 19:06:17
【问题描述】:

我的表结构如下:


+----------+------------------------+------+-----+------------------------------------------+----------------+
| Field    | Type                   | Null | Key | Default                                  | Extra          |
+----------+------------------------+------+-----+------------------------------------------+----------------+
| id       | int(10) unsigned       | NO   | PRI | NULL                                     | auto_increment |
| body     | varchar(200)           | NO   |     | Hey now!                                 |                |
| flags    | int(10) unsigned       | NO   |     | 0                                        |                |
| views    | int(10) unsigned       | NO   |     | 1                                        |                |
+----------+------------------------+------+-----+------------------------------------------+----------------+

并且我想选择“仅标记未超过其总视图 5% 且已被查看至少 5 次的行。”

这是我的查询:


SELECT id,body
FROM tablename
WHERE id NOT IN (
    SELECT id
    FROM tablename
    WHERE flags/views * 100 > 5.0
    AND views > 5
    ORDER BY id DESC
)
ORDER BY id DESC
LIMIT 6

我认为选择“标记超过总视图 30% 的每一行”将产生大量开销,尤其是当表增长到非常多的行时。有人可以帮我优化一下吗?

我还在考虑创建一个“flag_score”列,并在每次标记某些内容时更新它,这样我就可以在 flag_score 列上进行选择,而不是在选择中进行数学运算(并为自己节省额外的选择查询)。这听起来像是一个好方法吗?非常感谢。

编辑:我遇到的另一个问题是,如果我只是做类似的事情:


SELECT *
FROM tabelname
WHERE flags/views * 100 > 5.0
AND views > 5
ORDER BY id DESC
LIMIT 5

...如果 5 个帖子中有 4 个被标记,它只会返回 1 行!我希望语句返回 5 行。

【问题讨论】:

    标签: database-design mysql query-optimization spam-prevention


    【解决方案1】:

    数学不是很昂贵,所以只要你的条目少于 100 000 个,你就可以毫无顾虑地这样做。

    根据您自己的建议,您始终可以缓存条件:

    UPDATE tablename
    SET is_over_30_percent = (flags/views * 100 > 5.0)
    WHERE id='id_of_updated_entry'
    

    它的优点是您可以在 *is_over_30_percent* 上放置一个索引,这样查询根本不会占用任何性能。

    记得在 *id_of_updated_entry* dateid 上放置一个组合索引,以便索引可用于选择和排序(ORDER BY 很贵)。

    【讨论】:

    • 哦,顺便说一句:如果您关心性能,请尽量避免使用子选择。如果你必须有它,用你的程序语言来做。 MySQL 在优化它们方面非常糟糕。
    • 谢谢!我认为订购是相当昂贵的,但我不确定。
    • 这样就可以将 is_over_30_percent 存储为布尔值(又名 tinyint)?这听起来像一个好主意!我只是想存储实际分数(即 5、10 或 0 等),但如果它只是一个看起来更干净的布尔值!谢谢!
    • 没错。如果您不需要分数,为什么要存储它。它只是一个缓存,所以如果您需要实际分数,您可以随时更改它。
    • 太棒了,因为我无论如何都会在它被标记时进行更新,那很好。谢谢。
    【解决方案2】:

    我会说缓存是一种合理的方法,但这完全取决于系统中的读/写情况。如果人们一直在标记,那么 flag_score 值每次都需要更新,因此您的昂贵操作将会发生很多。

    另外,我不确定您是否会获得性能提升,但您可以执行 flag/views > .05 来保存每个查询的乘法,尽管我不认为这部分会那么昂贵。

    【讨论】:

    • 我猜这有点待定,但我不希望他们太疯狂。感谢您保存乘法。伤不起!
    猜你喜欢
    • 2014-11-12
    • 2016-03-20
    • 2011-02-07
    • 2012-07-07
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多