将私人消息“正文”字段存储在单独的表中以获得速度增益

时间:2013-01-14 13:15:19

标签: php mysql select ifnull

我为我的用户设置了一个私人消息系统,我在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”,并且不知道是否可以这样。

一般来说,可以判断这是否会减少数据库/加速查询的大小?

3 个答案:

答案 0 :(得分: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_table的主键与message_table的主键相同。即每个键只出现在消息表或两个表中,具有相同键的行属于一起。在这些情况下,可以通过将message_table.message_short_body设置为NULL来对邮件是否在另一个表中进行编码。

答案 1 :(得分: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;

答案 2 :(得分: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个条目的消息表的测试场景。每10个人都有一个长文本。 from_id和to_id消息是从50个用户中随机选择的。

第1部分:速度

使用单独的文本表进行第二次尝试将使 BIGGGGGG加速。第一次尝试的平均查询时间为 ~1.6 秒。第二个只有 ~0.28 秒!!!!

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

第2部分:数据库大小

数据库的大小会略有增长,因为人们可能已经预期到了。来自文本的附加索引使我的数据库增长约10%

结论:在单独的表格中存储大文本是一个的想法。在您的情况下,它将提高查询性能高达80%,而磁盘成本略高于10%。