3

我为我的用户创建了一个私人消息系统,该系统是在 php 中使用 mysql 后端创建的。系统会删除旧消息,但通常保留超过 500,000 条消息。目前所有数据都包含在一个表中:

message_table
    message_id (int 11)
    message_from_id (int 11)
    message_to_id (int 11)
    message_timestamp (int 11)
    message_subject (varchar 50)
    message_text (text)

大多数消息都很短,所以我正在考虑将系统更改为:

message_table
    message_id (int 11)
    message_from_id (int 11)
    message_to_id (int 11)
    message_timestamp (int 11)
    message_subject (varchar 50)
    message_short_body (varchar 50)
    message_text_id (int 11)

text_table
    text_id (int 11)
    text_body (text)

然后,如果输入了一条短消息,它将在“message_short_body”下输入,如果更长,将添加到“text_table”,“text_id”存储为“message_text_id”。当消息被访问时,我会得到类似的东西:

SELECT * FROM message_table LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id IF message_table.message_text_id != 0 WHERE message_table.message_to_id = $user_id

我添加了“IF message_table.message_text_id!= 0”,不知道这样的事情是否可行。

作为一般规则,是否可以判断这是否会减少数据库的大小/加快查询速度?

4

3 回答 3

2

我添加了“IF message_table.message_text_id!= 0”,不知道这样的事情是否可行。

text_id = 0除非您的 中实际上有一行,否则text_table没有必要这样做。只需省略IF并使用以下查询:

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body,
       …
FROM message_table
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id
WHERE message_table.message_to_id = $user_id

在性能方面,如果将条件添加到连接条件中,引擎可能可以更有效地优化事物

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body,
       …
FROM message_table
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id
                    AND message_table.message_text_id != 0
WHERE message_table.message_to_id = $user_id

您还可以尝试使用子查询的方法:

SELECT IF(message_text_id = 0, message_short_body, (
  SELECT text_table.message_short_body
  FROM text_table
  WHERE text_table.text_id = message_table.message_text_id)) AS body,
       …
FROM message_table
WHERE message_table.message_to_id = $user_id

这样做的好处是,如果不需要,则不执行搜索text_table,但缺点是对带有长消息的每个案例执行单独的查询。我希望上述查询更好,但我不确定。

作为一般规则,是否可以判断这是否会减少数据库的大小/加快查询速度?

您必须进行基准测试,因为这取决于用例。如果您的大多数查询从文本以外的字段中检索数据,那么较小的表将使这些查询更快,从而提高性能。另一方面,如果您通常希望正文与消息的其余部分一起使用,那么您最终可能会得到更差的性能。

您还应该使用基准来区分上述不同的替代方案。

在数据库大小方面,您可能会看到增加:文本数据的存储要求大致相同,但额外表的索引将花费您。

我想如果这是我的架构,我会删除message_text_id,而是将主键text_tablemessage_table. 即每个键要么只出现在消息表中,要么出现在两个表中,并且具有相同键的行属于一起。在这些情况下,可以通过设置message_table.message_short_body为来对消息是否在另一个表中进行编码。NULL

于 2013-01-14T16:19:44.967 回答
0

试试这个:

SELECT *, IFNULL(tt.text_body,  mt.message_short_body) textBody 
FROM message_table mt 
LEFT JOIN text_table tt ON tt.text_id = mt.message_text_id 
WHERE mt.message_to_id = $user_id;
于 2013-01-14T13:29:21.863 回答
0

我添加了“IF message_table.message_text_id!= 0”,不知道这样的事情是否可行。

您正在寻找的查询是这样的:

SELECT
  IFNULL(t.text, m.short_text) AS text
  -- other columns may follow
FROM messages2 m
LEFT JOIN texts t on m.text_id = t.id
WHERE to_id = A_USER_ID

作为一般规则,是否可以判断这是否会减少数据库的大小/加快查询速度?

是的,有可能!至少可以测试一下。我已经做到了。我创建了一个包含 500.000 个条目的消息表的测试场景。每十分之一都有一个长文本。消息 from_id 和 to_id 是从 50 个用户中随机选择的。

第 1 部分:速度

第二次尝试,使用一个单独的文本表,将给出一个BIGGGGGG 加速。第一次尝试的平均查询时间约为 1.6秒。仅第二个~0.28秒!!!!

回答这个问题:是的,它更快!:)

第 2 部分:数据库大小

正如预期的那样,数据库的大小将略有增长。来自文本的附加索引让我的数据库增长了约 10%

结论:将大文本存储在单独的表中是一个主意。在您的情况下,它将以大约 10% 的磁盘成本将查询性能提高多达 80%。

于 2013-01-14T13:34:25.580 回答