繁体   English   中英

如何提高此sql查询的性能?

[英]How to improve performance of this sql query?

(我在PHP和MySQL上工作)

这是一种情况:通过ajax请求,我每隔10秒检查一次用户所属日历中是否有新内容。

每个日历都有一些要检查的内容(w / e是日历或其他元素,但是在这种情况下,它是日历),所以我做了一个“大”查询以返回每个日历的所有数据,并且我用php处理,然后用js处理(弹出通知或w / e)。

要检查的三件事:

  • 自他上次访问日历以来,是否有“日期”修改?
  • 自从他上次看到聊天日历以来,有没有新话题?
  • 有没有要求加入日历的请求吗?

我是这样做的:

SELECT DISTINCT
  ci.ci_cid as c_id,
  MAX(cc.cc_timestamp) as chat_lastmsg, umchat.um_value as chat_lastview,
  MAX(cr.cr_id) as request_id,
  cmodif.cm_value as modification_timestamp,
  umodif.um_value as modification_view
FROM c_individuals as ci
  LEFT JOIN c_chats as cc ON cc.cc_cid = ci.ci_cid
   LEFT JOIN u_metas as umchat ON (umchat.um_uid = ci.ci_ciuid AND umchat.um_cid = ci.ci_cid AND umchat.um_name = "chat_last_view")
  LEFT JOIN c_requests as cr ON (cr.cr_cid = ci.ci_cid AND cr.cr_answer = "0")
  LEFT JOIN c_metas as cmodif ON (cmodif.cm_cid = ci.ci_cid AND cmodif.cm_name = "last_modifications")
   LEFT JOIN u_metas as umodif ON (umodif.um_uid = ci.ci_uid AND umodif.um_cid = ci.ci_cid AND umodif.um_name = "last_view")
WHERE ci.ci_uid = :u_id
GROUP BY ci.ci_cid
  • c_individuals表具有日历中的用户。
  • u_metas表具有用户的元数据,其中包括um_uid (用户ID), um_cid (与元数据有关的日历ID), um_name (元数据的名称), um_value (元数据的值)
  • c_requests表包含请求信息(u_id,c_id,答案和内容)

我的查询给了我我想要的东西,意思是:

0 => 
array (size=6)
  'c_id' => string '50' (length=2)
  'chat_lastmsg' => null
  'chat_lastview' => null
  'request_id' => null
  'modification_timestamp' => string '1488878397.703508' (length=17)
  'modification_view' => string '1488877914.048585' (length=17)
1 => 
array (size=6)
  'c_id' => string '51' (length=2)
  'chat_lastmsg' => string '1485326492' (length=10)
  'chat_lastview' => string '1488470529' (length=10)
  'request_id' => null
  'modification_timestamp' => string '1488878397.703508' (length=17)
  'modification_vue' => string '1488878065.811320' (length=17)

但是老实说,我认为这有点慢。 如果不进行处理,那么仅要获取查询结果,就需要3.5秒的时间来重复进行1000次。

没什么大不了的,但是对于潜在的大量用户,此查询会重复很多次。

所以我的问题是:有什么办法可以改善它,或者我对此有好处吗?

谢谢您的时间,对不起,我的英语不好。

您发布的查询没有发现任何问题,只是因为您正在执行GROUP BY所以您不需要DISTINCT 另外,请确保在JOIN ON条件和WHERE条件中使用的列上具有正确的索引。

更多的是系统/数据库设计问题,而不是查询设计。

该查询看起来足够了,并给出了您期望的结果,所以很好(尽管不确定为什么需要LEFT联接-但这取决于您的数据。)

在系统设计空间中要考虑的事项:

  • 对数据库结构进行非规范化-每当您输入c_chat或c_request等时,您都可能希望针对用户存储最新的时间戳记,因此您不进行联接-这非常慢。

  • 您可以从更靠近服务器的缓存(例如Memcache)中受益吗? 如果您有很多请求,那么在数据库运行缓慢的情况下,可能需要调查一下。 如果要对数据库进行非规范化,则可能不需要缓存。

  • 如果您不仅使用Id,还可以索引在WHERE中用作过滤器的任何内容

作为记录,

我终于找到了更快的东西(在我的“基准测试”中,它快了五到七倍)。

事实是,我不需要获取信息(日期等),我只想知道是否有新内容,因为用户上次(无论何时,何时发布)都看到了它。

所以我做了这个(用法语,请不要打扰):

SELECT
  ci.ci_cid as c_id,
  (SELECT COUNT(cc_id)
    FROM c_chats 
    LEFT JOIN u_metas ON um_nom = "chat_derniere_vue" 
   WHERE cc_cid = ci.ci_cid AND um_uid = ci.ci_uid AND um_cid = ci.ci_cid AND CAST(cc_timestamp as decimal) > CAST(um_valeur as decimal)
  ) as chat,
  (SELECT COUNT(cr_id)
    FROM c_requetes
   WHERE cr_cid = ci.ci_cid AND ci.ci_ustatut = "titulaire" AND cr_reponse = "0"
  ) as notifications,
  (SELECT COUNT(cm_cid)
    FROM c_metas 
    LEFT JOIN u_metas ON um_nom = "derniere_vue"
   WHERE um_uid = ci.ci_uid AND um_cid = ci.ci_cid AND cm_cid = ci.ci_cid AND cm_nom = "derniere_modification_periodes" AND CAST(cm_valeur as decimal) > CAST(um_valeur as decimal)
  ) as modifications
FROM c_individus as ci
WHERE ci.ci_uid = :u_id 
GROUP BY ci.ci_cid

通过这种方式, chat给出了带有新消息的聊天次数, notifications给出了未应答请求的数量, modifications给出了带有新日期的日历的数量。

和“多田”!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM