Mysql php 私信邮件系统

Mysql php private email like messaging system

我正在为我的应用构建一个小型消息传递系统,主要想法是有 2 个表。 Table1 条消息

Id,sender_id,title,body,file,parent_id

这是消息的存储位置,与接收消息的人分离以允许多个收件人。

父级 如果是回复,我会 link 到父级消息,文件是一个 blob,用于存储附加到消息的单个文件

Table 2 message_users

Id,thread_id,user_id,is_read,stared,deleted

Link 父线程到目标用户,

现在我可以为单个用户统计未读消息

Select count(*) from message_users where user_id = 1 and is_read is null

要统计他收件箱中的所有邮件,我可以做到

Select count(*) from message_users where user_id = 1;

问题是如何在单个优化查询中结合两者?

在 MySQL 中,当您计算一个字段时,它只计算该字段的非空出现次数,因此您应该可以这样做:

SELECT COUNT(user_id), COUNT(user_id) - COUNT(is_read) AS unread
    FROM message_users 
    WHERE user_id = 1;

未经测试,但应该能为您指明正确的方向。

您可以将 sum 与 CASE WHEN 子句一起使用。如果 is_read 为空,则将 +1 添加到总和,否则 +0.

SELECT count(*),
  SUM(CASE WHEN is_read IS NULL THEN 1 ELSE 0 END) AS count_unread
  FROM message_users WHERE user_id = 1;

因此,您正在尝试实现满足一个条件的总行数和满足额外条件的总行数的目标:

|---------|---------|
| total   | unread  |
|---------|---------|
| 20      | 12      |
|---------|---------|

因此需要具有以下形式的内容:

SELECT A total, B unread FROM message_users WHERE user_id=1

A 相当简单,您或多或少已经知道了:COUNT(Id).

B 稍微复杂一些,可能采用 SUM( IF(is_read IS NULL,1,0) ) 的形式——每次 is_read 不为空时加 1;条件将取决于您的数据库细节。

或者 B 可能看起来像: COUNT(CASE WHEN is_read IS NULL THEN 1 END) unread -- 这就是说 'when is_read is null, count another 1';条件将取决于您的数据库细节。

总计:

SELECT COUNT(Id) total, COUNT(CASE WHEN is_read IS NULL THEN 1 END) unread FROM message_users WHERE user_id=1

或:

SELECT COUNT(Id) total, SUM( IF(is_read IS NULL,1,0) ) unread FROM message_users WHERE user_id=1

就优化而言,我不知道有比这更快的查询。 (如果它确实存在,我很想知道它!)如果您遇到性能问题,可能有一些方法可以加快速度:

  • 检查您的索引:使用内置工具 EXPLAIN 和一些阅读等
  • 使用缓存 and/or 预先计算值并将其存储在其他地方 -- 例如有一个字段 unread_messages 反对 user 并直接获取此值。显然需要一些写时失效,或者确实需要一些服务 运行 使这些值保持最新。有很多方法可以实现这一点,MySQL 中的工具、自己动手等等等等。
  • 简而言之,从需求和一些真实数据开始优化。 (我的查询需要 0.8 秒,我需要在 0.1 秒内得到结果,并且它们需要在 100% 的时间内保持一致——我怎样才能做到这一点?)然后你可以调整和试验SQL,服务器运行的硬件(也许?),caching/pre-calculate 在不同的点等