1、因为之前没做过大数据处理项目,陆续在这里请教过不少类似的问题,很多大侠热心的帮助了我。
为了方便这里的大侠们了解,我尽量仔细的说明:
之前的三个帖子,比较新一点,回复过的大侠可以很快的了解我的问题所在:
http://topic.csdn.net/u/20090907/10/627bfeec-8bda-4d99-aded-e13435e7c4fe.html
http://topic.csdn.net/u/20090907/16/80f35fbd-3c6c-4ca0-80f7-d55806bf0ddf.html
http://topic.csdn.net/u/20090901/09/b3cd8e71-19be-4694-b43b-0e57cdf4bef2.html
2、针对举例的第二个贴子,为了方便描述,我在这里根据大侠的提议,提出我这边数据搜索的整个问题,分数100;如果系统允许的话,我可以加分数,这个系列问题困扰了我很久;本来我还在尝试用前面几楼提议的去优化,但是感觉真的怎么优化都不咋样····现在50多W的数据,搜索的时候已经很慢了,特别是关键字没有匹配的时候,会全表遍历2边,很慢。(一遍是获取相关总记录数:用于分页(用的是开源的AspNetPager),一遍是获取相关的记录)
3、简单介绍一下这个数据库和硬件,主要用来查询一些信息,目前50W左右数据,以后的话,至少是几百w的数据,甚至是上kw(这个目前先不考虑);存放的是独立托管的一台至强系列服务器,4核,4G内存。数据库和程序放开存放不同的盘符(也可以做到分开存放到2台服务器--如果效率会快的话);系统如果说要跟什么像,有点类似搜索引擎。
4、数据库表:相关的几张表简单描述: InfoTmp、InfoReal、KeyTmp、KeyReal、MyCounry、MyCategory、MyTopic
【InfoTmp】:用于存放临时数据,这些数据都是人工添加的,只有通过审核才会加入InfoReal表;
【InfoReal】:正式数据,用于前台显示;
【KeyTmp】:第3点说到有点类似搜索引擎,就是在这里,用户每搜索一次的关键字,会加入到这个KeyTmp,然后通过计划任务,每天24点,整理后(相同的关键字合并,统计数量;如果正式key表存在则加数量,不存在则新加记录)加入KeyReal;
【MyCounry、MyCategory、MyTopic】:分别存放的是国家,类别,主题信息。
表结构简单举例:
【InfoReal】
[CI_ID],[CI_CorpName],[Country_Continent],[Country_ID],[C_FatherID],[C_ChildID],[CI_MobilePhone],[CI_StateFlag],[CI_CreateTime],[CI_ModifyTime],[CI_ClickTimes],[CI_BuyTimes],[CI_Keywords],[CI_SearchKey]
,[topic_ID],[CI_Charge].......
主要问题所在的存放内容举例:
-----------------------------
CI_ID C_FatherID C_ChildID
10024 1024,1025,1056, 1045,1088,1045,1054,1063,
10025 1024,1025,1056, 1045,1088,1045,1054,1063,
-----------------------------
-----------------------------
【MyCategory】存放内容举例: C_FatherID:0表示为大类
C_ID C_FatherID
1024 0
1045 1024
1054 1025
-----------------------------
-----------------------------
【MyCounry】存放内容举例: Country_Continent:表示洲,1亚洲,2欧洲....
Country_ID Country_Continent
1024 1
1045 2
1054 3
-----------------------------
-----------------------------
问题描述:最初的主表设计,信息对于类别(国家,类别,主题是唯一对应的),后来项目已经做好了,领导要求修改:一条信息可以属于多个小类别(也可以属于不同的大类)。于是我把InfoReal的[C_FatherID],[C_ChildID]都改为了字符型,存放的内容见上面内容举例。
再则,最初是没有C_FatherID和Country_Continent;最初数据搜索,都是选择一个大类,然后选择相关小类;国家也一样,先选择洲,然后选择具体国家;后来需求改变,改成了,可以选择1个洲或者多个国家(可以属于不同洲);1个大类或者多个小类(可以属于不同大类);同时还有主题,价格,排序等一些附加搜索条件...于是我陆续在这里请教了一些问题。最初因为项目结构都搞好了,我实在不想改动,后来结合大家的意见和搜索速度实在慢,感觉非常有必要改动。于是我开了这个帖子。
下面我贴出取数据列表的存储过程并做简单说明:
- SQL code
ALTER PROCEDURE [dbo].[corpListRealUser] -- Add the parameters for the stored procedure here @myContinent varchar(10), --传入洲的值 @myCountrys varchar(50), --传入国家的值;已处理成sql条件语句,后面说明 @myCategoryB varchar(10), --传入大类的值 @myCategorys varchar(50), --传入小类的值;已处理成sql条件语句,后面说明 @myTopic decimal, --传入主题的ID @myPriceL int, --传入价格范围的起始 @myPriceH int, --传入价格范围的终点 @myOrderType int, --传入排序类型(按时间,价格,点击量,购买量) @myOrderFlag int, --传入排序标志(升序还是降序) @mySerKeyword varchar(500), --传入关键字 @CI_StartRecordIndex int, --传入分页起始点 @CI_EndRecordIndex int --传入分页终结点ASBEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here declare @str varchar(max),@strOrder varchar(200) set @str='' if @myTopic>0 begin set @[email protected]+'and topic_ID='+rtrim(@myTopic) end if @myPriceH<500 begin set @[email protected]+' and CI_Charge BETWEEN '+rtrim(@myPriceL)+' AND '+rtrim(@myPriceH) end if @myContinent<>'0' begin set @[email protected]+'and Country_Continent='+rtrim(@myContinent) end if @myCountry<>'0' begin set @[email protected][email protected] end if @myCategoryB<>'0' begin set @[email protected]+'and C_FatherID='+rtrim(@myCategoryB) end if @myCategoryS<>'0' begin set @[email protected][email protected] end[b]--这里的myCountrys和myCategorys都已在前台程序处理成:and (charindex(',195,',','+InfoReal.C_ChildID)> 0 or charindex(',81,',','+InfoReal.C_ChildID)> 0 or charindex(',64,',','+InfoReal.C_ChildID)> 0-----这种语句,结合我最上面举例到的三个帖子,大侠的给我建议是把charindex改为like;然后把or,改为union all模式-----因为语句的问题,还有其他条件,改成union all我也是比较的懵,不太会改;然后第二个帖子提到了,结构问题,很关键,让我意识到我不改结构,其实速度是无法改变慢的局面的。[/b] if @mySerKeyword<>'' begin set @[email protected]+'and (CI_SearchKey like ''%'+ @mySerKeyword +'%'')' end--以下部分是排序条件 set @strOrder='' declare @orderPX varchar(10) if @myOrderFlag=1 set @orderPX=' asc' else set @orderPX=' desc' if @myOrderType=1 begin set @[email protected]+'order by [email protected] end else if @myOrderType=2 begin set @[email protected]+'order by [email protected] end else if @myOrderType=3 begin set @[email protected]+'order by [email protected] end else if @myOrderType=4 begin set @[email protected]+'order by [email protected] end else begin set @[email protected]+'order by [email protected] end --下面部分简单说明:1、infoReal表为了加快速度,最初关键字搜索匹配是跟CI_CorpName和CI_Keywords和CI_Profile用or连接;后来加了CI_SearchKey这个字段,取值是把前面三个字段值结合,然后截取250个字符做的搜索关键字。2、为了加快速度,我最大也只取600条数据;如果数据库匹配的数据多,速度是相对快点,如果没有匹配或者没有达到600条,就会表全部扫描一遍(加上分页读取记录总数,相当于2边),速度就相对比较慢。3、搜索相关的条件字段我都有做索引,CI_ID是主键唯一,聚集索引我是做在了CI_SearchKey这个字段上(就是搜索关键字)4、CI_StateFlag=1 or CI_StateFlag=3这里我用了OR结构是不是索引也不起效果了??这个字段是用来判断数据是否在前台显示的判断标识符。 declare @sql varchar(max) set @sql = 'select * from (select top 600 row_number() over ('+rtrim(@strOrder)+',CI_ID desc)as Row, CI_ID,CI_CorpName,CI_Profile,CI_StateFlag,CI_Charge,CI_ModifyTime,CI_ClickTimes,CI_BuyTimes,Country_ID from TE_CorpInfoReal where (CI_StateFlag=1 or CI_StateFlag=3) [email protected]+') t WHERE 1=1 AND Row BETWEEN '+rtrim(@CI_StartRecordIndex)+' AND '+rtrim(@CI_EndRecordIndex)+' order by row' exec(@sql)END