asp.net 相关文章实现方法

前言:大家或许会觉得很惊讶:为什么灵感之源会讨论SQL?或许应该这样说吧:搞业务系统,不跟SQL扯上关系似乎比较难。

  场景:在开发某系统的过程中,我遇到了要实现“相关文章”功能:任何文章都可以定义“关键字”,每篇文章依靠这个“关键字”来确定其它文章是否跟它相关,如果没有定义关键字,则可能需要使用全文检索来实现了,这是别的话题了。

  思考:因为允许关键字可以通过“,”分隔符号来定义多个,所以加大了难度。经过思考,可以通过在保存文章的时候便分解关键字,建立一关键字表,把所有关键字逐个按对应的文章ID来保存。并决定采用纯SQL存储过程的办法,因为这种重复的操作,与其用通用函数,倒不如用预编译的存储过程更加快,这样能把所有处理都留給SQL Server。

  解决方案1:首选要做的是在原有文章表(Details)的基础上建立相关文章表(RelatedDetails),字段包括ItemID(主键)、DetailID(文章ID)和Keyword(关键字)。以下是主要存储过程:

  1、UpdateRelatedDetails:更新相关文章关键字

  

复制代码 代码如下:

  CREATE procedure dbo.UpdateRelatedDetails

  @DetailID INT,

  @Keywords NVARCHAR(500)

  AS

  EXEC DeleteRelatedDetails @DetailID

  DECLARE @I INT

  DECLARE @Keyword NVARCHAR(50)

  SET @Keywords=REPLACE(@Keywords,',', ',')

  SET @Keywords=REPLACE(@Keywords,';', ',')

  SET @Keywords=RTRIM(LTRIM(@Keywords))

  SET @I=CHARINDEX(',', @Keywords)

  WHILE @I>=1

  BEGIN

  SET @Keyword=LEFT(@Keywords, @I-1)

  INSERT INTO DetailKeywords (DetailID, Keyword) VALUES(@DetailID, @Keyword)

  SET @Keywords=SUBSTRING(@Keywords, @I+1,LEN(@Keywords)-@I)

  SET @I=CHARINDEX(',', @Keywords)

  END

  IF @Keywords<>''

  INSERT INTO DetailKeywords (DetailID, Keyword) VALUES(@DetailID, @Keywords)

  GO

  2、DeleteRelatedDetails:删除原有相关文章关键字

  

复制代码 代码如下:

  CREATE PROCEDURE dbo.DeleteRelatedDetails

  @DetailID INT

  AS

  DELETE FROM DetailKeywords WHERE DetailID=@DetailID

  GO

  3、GetRelatedDetails:获取相关文章,其中Details就是文章表

  

复制代码 代码如下:

  CREATE procedure dbo.GetRelatedDetails

  @DetailID INT

  AS

  DECLARE @Keywords NVARCHAR(500)

  SELECT @Keywords=Keywords FROM Details WHERE ItemID=@DetailID

  IF @Keywords<>''

  BEGIN

  SELECT DISTINCT d.ItemID, d.Subject, d.ItemFile

  FROM Details d RIGHT OUTER JOIN DetailKeywords k ON k.DetailID=d.ItemID WHERE d.ItemID <> @DetailID AND @Keywords LIKE '%'+k.Keyword+'%'

  END

  GO

  解决方案2:原来的做法是文章表和关键字表,关键字表可能会存在大量重复的关键字,所以采用中间表,而关键字不再重复。

  设计:首选要做的是在原有文章表(Details)的基础上建立关键字表(DetailKeywords),字段包括ItemID(主键)和Keyword(关键字),还有中间表DetailsKeywords,包括DetailID(文章ID)和KeywordID(关键字ID)。以下是主要存储过程:

  UpdateRelatedDetails:更新关键字

  

复制代码 代码如下:

  CREATE procedure dbo.UpdateRelatedDetails

  @DetailID INT,

  @Keywords NVARCHAR(500)

  AS

  SET NOCOUNT ON

  EXEC DeleteRelatedDetails @DetailID

  DECLARE @I INT

  DECLARE @Keyword NVARCHAR(50)

  DECLARE @KeywordID INT

  SET @Keywords=REPLACE(@Keywords,',', ',')

  SET @Keywords=REPLACE(@Keywords,';', ',')

  SET @Keywords=RTRIM(LTRIM(@Keywords))

  SET @I=CHARINDEX(',', @Keywords)

  WHILE @I>=1

  BEGIN

  SET @Keyword=LEFT(@Keywords, @I-1)

  EXEC AddRelatedDetailKeyword @DetailID, @Keyword

  SET @Keywords=SUBSTRING(@Keywords, @I+1,LEN(@Keywords)-@I)

  SET @I=CHARINDEX(',', @Keywords)

  END

  IF @Keywords<>''

  EXEC AddRelatedDetailKeyword @DetailID, @Keywords

  SET NOCOUNT OFF

  GO

  AddRelatedDetailKeyword:添加单个关键字

  

复制代码 代码如下:

  CREATE procedure dbo.AddRelatedDetailKeyword

  @DetailID INT,

  @Keyword NVARCHAR(50)

  AS

  SET NOCOUNT ON

  DECLARE @KeywordID INT

  SELECT @KeywordID=ItemID FROM DetailKeywords WHERE Keyword=@Keyword

  IF @KeywordID IS NULL

  BEGIN

  INSERT INTO DetailKeywords (Keyword) VALUES(@Keyword)

  SET @KeywordID=IDENT_CURRENT('DetailKeywords')

  END

  INSERT INTO DetailsKeywords (DetailID, KeywordID) VALUES(@DetailID, @KeywordID)

  SET NOCOUNT OFF

  GO

  DeleteRelatedDetails:删除之前的关键字,存在点问题

  

复制代码 代码如下:

  CREATE PROCEDURE dbo.DeleteRelatedDetails

  @DetailID INT

  AS

  SET NOCOUNT ON

  --这里还有其它东西没有判断和删除

  DELETE FROM DetailsKeywords WHERE DetailID=@DetailID

  SET NOCOUNT OFF

  GO

  GetRelatedDetails:根据某文章ID获取相关文章

  

复制代码 代码如下:

  CREATE procedure dbo.GetRelatedDetails

  @DetailID INT

  AS

  SELECT DISTINCT d.ItemID, d.Subject FROM Details d, DetailKeywords k, DetailsKeywords s

  WHERE d.ItemID = s.DetailID AND k.ItemID=s.KeywordID AND d.ItemID<>@DetailID

  GO

  我贴一下性能比较,环境是30万条记录,机器是PIII 800+300多内存,硬盘是7200转:

  

复制代码 代码如下:

  --第1种,两表情况

  --select a.* from Article a,ArtKey2 b

  --where a.ArtID=b.ArtID and b.KeyValue='科技9'

  --第2种,三表情况

  --select a.* from Article a,ArtKey1 b,

  --(select KeyID from KeyValue where KeyValue='科技9') c

  --where a.ArtID=b.ArtID and b.KeyID=c.KeyID

  --第3种,三表情况

  --select * from Article where ArtID in

  --(select ArtID from ArtKey1 where KeyID in

  --(select KeyID from KeyValue where KeyValue='科技9'))

  优化Sql语句主要是通过在“执行计划”图所显示的IO成本,以及cpu成本来分析执行效率。在SQL查询分析器的执行计划中,IO成本+CPU成本=本步成本。

  三种SQL语句在同一批处理中的执行分析结果:

  1、占14.22%,实际执行成本为2.96。

  2、占43.08%,实际执行成本为9.96。

  3、占42.70%,实际执行成本为8.88。

  第一种执行成本远小于后者,且执行计划也比后者简洁得多,显然第一种要优于其它两种。执行计划简洁不是优越的标准,但SQL语句写得不够简洁,通常是为了满足业务需求不得已写出复杂语句。第2种与种3种的执行计划只是在最后一步不同,前者是inner join,后者是Right Semi Join。