西西河

主题:【求助】实现送花功能的SQL语法求助,回复者花 -- 卷心菜

共:💬23 🌺28
全看树展主题 · 分页首页 上页
/ 2
下页 末页
家园 你的要求是有难度的

你的原始查询是列出某个发言者参与过的所有主题(不管他是不是这个主题的发起人)。对于一个主题,当他只是跟帖者的时候,ibf_posts中对应author_id记录的row并不是你想输出rep_inc(花)和rep_dec(草)的row,这才是问题的关键。所以,如果你不想分两步做的话,就要一点技巧,我这里用“别名”(Alias)。

$query = "SELECT DISTINCT(post1.author_id), ibf_topics.*, post2.rep_inc, post2.rep_dec

FROM ibf_topics

LEFT JOIN ibf_posts AS post1 ON

(ibf_topics.tid=post1.topic_id AND post1.author_id=".$ibforums->member['id'].")

LEFT JOIN ibf_posts AS post2 ON

(ibf_topics.starter_id=post2.author_id AND ibf_topics.start_date=post2.post_date)

WHERE ibf_topics.forum_id=".$this->forum['id']."

家园 这种写法效率太低

如果你使用Query的方式来计算,不管怎么样效率都太低,帖子数一多性能马上急剧下降,最好是改用另外一种方式就是增加新的表用来记录花草的数量,显示时直接引用比你每次都全表扫描来的好.计算积分可以用DTS job来计算,我相信CCthere也是用类似的方式来做的.有兴趣可以具体再聊

家园 哈,这正是我需要的

用这个应该可以同时满足两个功能的要求。

家园 显示时确实是直接引用

那个Query并不是扫描全表来计算花草数量,Query是为了找出跟某主题相关的花草数字究竟储存在另一个表中的哪一行,然后把它join过来。就算新增一个表专门记录花草数量,也还是需要类似的query吧?当然一个更直接的办法就是在开帖时于ibf_topics表中记录下首发帖的id,这样就可以直接知道要拿另一个表中的哪一行。

至于计算积分,我在member表中有两栏是花/草数量,每次有人送花/扔草就一并写入该人相关的栏,显示积分时就直接引用。

家园 重复计算就是浪费

从你的Query来看,每次需要显示板块列表时,你都需要运行这个Query,对吧?同样的计算系统需要重复做多次,为什么不优化一下,例如在ibf_topics表中加字段保存首发贴的花草数,或者单独加一个表以免影响原有表结构,只有当首发贴有送花草时才重新计算,这样不更好吗? 你的Query就可以简化成

select ibf_topics.*, ibf_topics_extend.rep_inc,ibf_topics_extend.rep_dec from ibf_topics,ibf_topics_extend on ibf_topics.topic_id = ibf_topics_extend.topic_id

如果你不想做上面的修改的话,回到你现在的Query,也有可以优化的地方,那就是不要使用Left Join,这会让系统先将ibf_topics和ibf_posts中的全部记录进行外键匹配后再根据forum_id做过滤,这就是我前面帖子说的全表扫描,如果千万级甚至更多的记录数,left join对资源的消耗就会大到你不能忽视的地步,这时候我们可以用函数来代替left join,你可以在性能监视器中观察两种方法的优劣.

Sample function fn_Get_rep_inc

(

@topic_id INT,

@author_id INT,

@post_date INT

)

returns @ref_inc INT

as

begin

select @ref_inc = ibf_posts.rep_inc from ibf_posts where toic_id=@topic_id and author_id=@author_id and post_date = @post_date

return

End

这样你的Query可以改成

select ibf_topics.*, fn_Get_rep_inc(ibf_topics.topic_id,ibf_topics.starter_id, ibf_topics.starter_date), fn_Get_rep_dec(ibf_topics.topic_id,ibf_topics.starter_id, ibf_topics.starter_date) from ibf_topics WHERE ibf_topics.forum_id=".$this->forum['id']."

家园 也不能说得太绝对

首先,改变数据结构对已经运行的系统来说并非轻而易举。另外,记录花草数的字段在ibf_posts中是必需的(回帖也可能有送花丢草),再在ibf_topics表中加字段显然是冗余。

至于用函数来代替left join,这是一种优化的方法。好处是performance大幅度地提高。但代价是失去了标准SQL的简洁、通用,同时也阻止了数据库系统本身对查询的优化。所以,应该根据数据量的大小和用户对反应时间的要求综合评估,决定是否采用和采用何种优化方法。

家园 现在规模还不大

也就是十万左右,在可见的将来也不会增长太多,所以暂时用left join应付一下就算了,看上去还是很快的。以后如有需要再用function优化。

其实我从来没有正经学过SQL,连JOIN啊GROUP啊这些基本功能都一知半解,SQL写function这种事情不说我都不知道,呵呵。

家园 具体需求决定具体方法

就你目前的情况,left join的确是够用并且能用的,但是如果仅仅是考虑能用是不够的,要能够根据不同的需求和环境给出不同的Solution,才是真正需要去掌握的东西,当然你如果不是IT界人,就不用考虑这些了.

全看树展主题 · 分页首页 上页
/ 2
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河