百度2008笔试题(关于SQL)

本文介绍了一个简单的论坛系统的数据库设计,包括表结构、索引选择及分页查询算法。设计覆盖了用户信息、发帖和回复等功能,适用于日访问量300万、日更新帖子10万的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

rel="File-List" href="file:///C:%5CDOCUME%7E1%5C%E4%B8%B0%E5%9B%BD%E6%A0%8B%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

题目:一个简单的论坛系统,以数据库储存如下数据:用户名,email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容。每天论坛访问量300万左右,更新帖子10万左右。请给出数据库表结构设计,并结合范式简要说明设计思路。

 

1.设计目标:注册进入论坛后,得到最近N条主题模式下的帖子(只显示titleusernameposttime),点击进入后显示主贴子和回复帖子,主贴主要有:titleusernamecontentposttime;恢复帖子主要有replytitlereplyusernamereplycontentreplyposttime。能够发帖更新数据,插入数据等

 

2.功能实现:

1)千万量级数据库的分页查询显示

2)主题模式下的主贴和回复贴的显示

3)主题模式下通过搜索nametitleposttime等参数来查询

 

3.数据库设计

使用MS SQL2000作为平台

CREATE DATABASE forum

go

use forum

 

CREATE TABLE [UsernameTable]

(

       --用户名(可以是中文)

       [username] [nvarchar](20) COLLATE Chinese_PRC_CI_AS NOT NULL,

       --email

       [email] [varchar](255) NULL,

       --homepage

       [homepage] [varchar](255) NULL,

       --tel

       [tel] [varchar](20),

       --设置主键

       primary key (username)

)ON [PRIMARY]

go

 

CREATE TABLE [PostTable]

(

       --本表的id号,也是主键

       [grid] [int] IDENTITY (1,1) NOT NULL,

       --发贴人

       [username] [nvarchar](20) COLLATE Chinese_PRC_CI_AS NOT NULL,

       --标题

       [title] [nvarchar](32) COLLATE Chinese_PRC_CI_AS NOT NULL,

       --内容

       [content] [nvarchar](255) COLLATE Chinese_PRC_CI_AS NULL,

       --回帖时间

       [posttime] [datetime] NOT NULL

)ON [PRIMARY]

go

 

CREATE CLUSTERED INDEX PK_IndexPostTime on PostTable(posttime)

CREATE NONCLUSTERED INDEX PK_IndexUsername on PostTable(username)

CREATE NONCLUSTERED INDEX PK_IndexTitle on PostTable(title)

go

 

CREATE TABLE [ReplyTable]

(

       --本表的id号,也是主键

       [grid] [int] IDENTITY (1,1) NOT NULL,

       --原帖id

       [postgrid] [int] NOT NULL,

       --回贴人

       [replyusername] [nvarchar](20) COLLATE Chinese_PRC_CI_AS NOT NULL,

       --标题

       [replytitle] [nvarchar](32) COLLATE Chinese_PRC_CI_AS NOT NULL,

       --内容

       [replycontent] [nvarchar](255) COLLATE Chinese_PRC_CI_AS NULL,

       --回帖时间

       [replytime] [datetime] NOT NULL,

)ON [PRIMARY]

go

 

CREATE CLUSTERED INDEX PK_IndexReplyTime on ReplyTable(replytime)

CREATE NONCLUSTERED INDEX PK_IndexPostgrid on ReplyTable(postgrid)

Go

 

PostTable中的gridReplytable中的postgrid1:N关系,但是不是foreign key 关系,删除posttable中的帖子,其回帖仍然存在,但是无入口,找不到。

 

4.分页查询

CREATE PROCEDURE dt_pagination3

@tblName   varchar(255),       -- 表名

@strGetFields varchar(1000) = '*', -- 需要返回的列

@fldName varchar(255)='',      -- 排序的字段名

@PageSize   int = 10,          -- 页尺寸

@PageIndex int = 1,           -- 页码

@doCount bit = 0,   -- 返回记录总数, 0 值则返回

@OrderType bit = 0, -- 设置排序类型, 0 值则降序

@strWhere varchar(1500) = '' -- 查询条件 (注意: 不要加 where)

AS

declare @strSQL   varchar(5000)       -- 主语句

declare @strTmp   varchar(110)        -- 临时变量

declare @strOrder varchar(400)        -- 排序类型

 

set nocount on              --使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息

 

if @doCount != 0

 begin

    if @strWhere !=''

    set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere

    else

    set @strSQL = "select count(*) as Total from [" + @tblName + "]"

end

--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount0的情况

else

begin

 

if @OrderType != 0

begin

    set @strTmp = "<(select min"

set @strOrder = " order by [" + @fldName +"] desc"

--如果@OrderType不是0,就执行降序,这句很重要!

end

else

begin

    set @strTmp = ">(select max"

    set @strOrder = " order by [" + @fldName +"] asc"

end

 

if @PageIndex = 1

begin

    if @strWhere != '' 

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from [" + @tblName + "] where " + @strWhere + " " + @strOrder

     else

     set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["+ @tblName + "] "+ @strOrder

--如果是第一页就执行以上代码,这样会加快执行速度

end

else

begin

--以下代码赋予了@strSQL以真正执行的SQL代码

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["

    + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder

 

if @strWhere != ''

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["

        + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["

        + @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["

        + @fldName + "] from [" + @tblName + "] where " + @strWhere + " "

        + @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder

end

end 

exec (@strSQL)

GO

set nocount off

 

5.添加测试数据

1)往PostTable添加1,000,000条数据,每天发帖10,000条新贴,PostTable100w条数据

set nocount on

declare @i int

declare @j int

 

set @j = 1

declare @post_time datetime

set @post_time = '2008-8-1'

 

declare @titles nvarchar(32)

declare @contents nvarchar(255)

declare @usernames nvarchar(20)

 

 

while @j<=100

begin

       set @i =1      

       while @i<=10000

       begin

              set @usernames = '丰国栋'+cast(@i as varchar(10));

              set @titles = '医学图像增强 '+cast(@i as varchar(10))

              set @contents = 'DR医学图像增强 '+cast(@i as varchar(10))

              insert into PostTable(username,title,content,posttime) values(@usernames,@titles,@contents,@post_time+@j-1+0.00009*@i)

              set @i = @i + 1

       end

       set @j = @j + 1

end

go

set nocount off

2)平均每个帖子10条回复,共有1000w条数据

set nocount on

declare @i int

declare @j int

declare @post_time datetime

declare @titles nvarchar(32)

declare @contents nvarchar(255)

declare @usernames nvarchar(20)

declare @grid int

declare @gridtemp int

declare @k int

 

set @post_time = '2008-8-2'

set @j = 1

while @j<=100

begin

       set @i =1

       set @k = 0

       while @i<=10000

       begin

              set @grid = 1        

              while @grid <= 10

              begin

                     set @usernames = '丰国栋'+cast(@i as varchar(10));

                     set @titles = '医学图像增强 '+cast(@i as varchar(10))

                     set @contents = 'DR医学图像增强 '+cast(@i as varchar(10))

                     set @gridtemp = (@j-1) * 10000 + @i

                     rel="File-List" href="file:///C:%5CDOCUME%7E1%5C%E4%B8%B0%E5%9B%BD%E6%A0%8B%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"> insert into ReplyTable(postgrid,replyusername,replytitle,replycontent,replytime) values(@gridtemp,@usernames,@titles,@contents,@post_time+@j-1+0.00001*@k)                    

                     set @grid = @grid + 1

              end

              set @k = @k + 1                 

              set @i = @i + 1

       end

       set @j = @j + 1

end

go

set nocount off

 

6.测试结果

主题模式下对PostTable查询页

declare @d datetime

set @d=getdate()

exec dt_page PostTable,'grid,username,title,content,posttime','posttime',100,10000,0,1,''

select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

go

516ms(最后一页)

 

exec dt_page PostTable,'grid,username,title,content,posttime','posttime',100,1,0,1,''

0ms

 

exec dt_page PostTable,'grid,username,title,content,posttime','posttime',100,5000,0,1,''

rel="File-List" href="file:///C:%5CDOCUME%7E1%5C%E4%B8%B0%E5%9B%BD%E6%A0%8B%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

186ms

 

用得到的grid查询ReplyTable得到回复贴

 

7.讨论

1.分页算法中的fldName只能是唯一的,在以时间为clusterindex时,最多一天有24*60*60*1000= 86400000个数据,如果一天处理的数据达到1亿,甚至更多,如何处理?

2.并发数据在插入时,有没有可能出现两个getdate()是一样的情况?如果有,如何处理?

3.MS SQL2005中或更新的版本有没有比表变量,top等更好的分页方法?

4.表没有属性count数,不知道TableNum/pagesize的页表数,不然最多top(tablenum/2)。即上例最多186ms

exec dt_page PostTable,'grid,username,title,content,posttime','posttime',100,5000,0,1,''

rel="File-List" href="file:///C:%5CDOCUME%7E1%5C%E4%B8%B0%E5%9B%BD%E6%A0%8B%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

186ms
 

8Reference

http://blog.youkuaiyun.com/chenjinjie/archive/2007/05/28/1628355.aspx

摘要:

1)深入浅出理解索引结构

您可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)。我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。

2)何时使用聚集索引或非聚集索引

下面的表总结了何时使用聚集索引或非聚集索引(很重要)。

动作描述

使用聚集索引

使用非聚集索引

列经常被分组排序

返回某范围内的数据

不应

一个或极少不同值

不应

不应

小数目的不同值

不应

大数目的不同值

不应

频繁更新的列

不应

外键列

主键列

频繁修改索引列

不应

3)索引使用的误区

1、主键就是聚集索引

2、只要建立索引就能显著提高查询速度

3、把所有需要提高查询速度的字段都加进聚集索引,以提高查询速度

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值