我为我的用户设置了一个私人消息系统,我在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”,并且不知道是否可以这样。
一般来说,可以判断这是否会减少数据库/加速查询的大小?
答案 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%。