我爲NET狂官方面試題-數據庫篇答案

 題目:http://www.cnblogs.com/dunitian/p/6028838.htmlhtml

彙總:http://www.cnblogs.com/dunitian/p/5977425.htmlsql

說明:若有錯誤能夠批評指正,有更好寫法也能夠提點下~ 數據庫

 

1. 求結果:select "1"? 服務器

報錯,SQL裏面只有單引號,列如:'xx' 網絡

   

2. 查找包含"objs"的表?查找包含"o"的數據庫? 分佈式

select * from sys.objects where name like '%objs%' 函數

select * from sys.databases where name like '%o%'   性能

   

3. 求今天距離2002年有多少年,多少天? 測試

select datediff(yy,'2002',getdate()) 優化

select datediff(dd,'2002',getdate())  

   

4. 請用一句SQL獲取最後更新的事務號(ID)

 

select top 1 ID from ServerUpdateTime order by  LastUpdateDate desc  

   

5. 有以下兩個表:

①請查詢11 ~ 15記錄的User

只是解題用:

select top 5 * from (select row_number() over(order by [User].UserID) ID,* from [User]) UserInfo

where UserInfo.ID>=11 and UserInfo.ID<=15

和子查詢的對比圖:

 

 

真正項目每每查詢User完整信息:

--其餘寫法

select * from 

(

    select top 5 * from (select row_number() over(order by [User].UserID) ID,* from [User]) UserInfo

    where UserInfo.ID>=11 and UserInfo.ID<=15

) Temp

inner join User_Score on Temp.UserID=User_Score.UserID

   

--推薦寫法

select top 5 * from 

(

    select row_number() over(order by Temp.UserID) ID,* from 

    (

        select [User].UserID,UserName,UserType,ScoreID,Score from [User]

        inner join User_Score on [User].UserID=User_Score.UserID

    )Temp

) UserInfo

where UserInfo.ID>=11 and UserInfo.ID<=15  

   

依據:推薦寫法,看起來效率應該低點,但事實證實比其餘寫法效率高

②查詢用戶類型type=1總積分排名前十的user

 select top 10  [User].* from [User] 

 inner join User_Score on [User].UserID=User_Score.UserID

 where UserType=1

 order by Score desc 

 

③寫一條存儲過程,實現往User中插入一條記錄並返回當前UserId(自增加id)

--推薦寫法

if(Exists(select * from sys.objects where name=N'Usp_InsertedID'))

  drop proc Usp_InsertedID

go

create proc Usp_InsertedID

as

  insert into [User] output inserted.UserID values(N'張三蛋',3)

 

--另外一種寫法(SCOPE_IDENTITY()能夠獲得當前範圍內最近插入行生成的標示值)

if(Exists(select * from sys.objects where name=N'Usp_InsertedID'))

    drop proc Usp_InsertedID

go

create proc Usp_InsertedID

as

    insert into [User] values(N'李狗蛋',1)

    select scope_Identity()

go

 

--不推薦:(@@Identity就不必定是當前範圍內了)

if(Exists(select * from sys.objects where name=N'Usp_InsertedID'))

    drop proc Usp_InsertedID

go

create proc Usp_InsertedID

as

    insert into [User] values(N'張三章',2)

    select @@Identity

go

   

exec Usp_InsertedID

   

6. 請求出每一個班級的數學平均分,並按照高低進行排序

select avg(Score) AvgScore from Student

where Subject=N'數學'

group by Class

order by AvgScore desc  

   

7. 一個TestDB表有A,B兩個字段。

①寫一句SQL求出有重複值的記錄。

--解題專用

select * from TestDB

where A in

(

    select A from TestDB

    group by A,B

    having count(*)>1

)

order by A

   

--推薦:實際運用(真實環境下每每是爲了找出重複值而後刪掉)

select * from

(

    select row_number() over(partition by A,B order by A) ID,* from TestDB

) Temp

where Temp.ID>1

 

執行效率仍是有很大差距的,有圖有真相:

②請刪除重複項。(最好用兩種方法)

--傳統寫法:

select * into #Temp from (select distinct * from TestDB) A

drop table TestDB

select * into TestDB from #Temp

drop table #Temp

   

--推薦寫法(真正項目中基本上不會真刪)

delete Temp from (select row_number() over(partition by A,B order by A) ID,* from TestDB)Temp

where Temp.ID>1

   

8. 表中有A,B,C三列,用SQL實現:當A列>B列選擇A,不然選擇B,當B列>C列選擇B,不然選擇C

select

 (

    case

        when A>B then A

        else B

    end

 ),

 (

    case

        when B>C then B

        else C

    end

 )from ABC

   

9. 數據行列互換

轉換前:

轉換後:

select Name,

sum(

    case Courses

        when '語文' then Score else 0

    end

) 語文,

sum(

    case Courses

        when '數學' then Score else 0

    end

)數學,

sum(

    case Courses

        when '物理' then Score else 0

    end

)物理 from Student_Courses_Score

group by Name

 

10. 請統計每一個URL訪問次數,並按訪問次數由高到低的順序排序

select url,Count(*) n from WebUrl

group by url

order by n desc

 

順便打破一個僞結論:count(1)性能大於count(*)==》不要麻木相信優化,本身證明後再說~(PS:通常都是count(主鍵),有時候其餘狀況有大坑

 

11. 用戶註冊表中id是自增加的。

①請查詢出一天24h每小時註冊的人數

select datepart(hh,CreateTime) '小時',count(*) '註冊人數' from User_Register

where CreateTime>=convert(varchar(10),getdate(),120) and CreateTime <convert(varchar(10),dateadd(day,1,getdate()),120)

group by datepart(hh,CreateTime)

 

②請查詢第4條記錄

select * from (select row_number() over(order by ID) RId,* from User_Register) Temp

where RId=4

 

③請查詢ID重複次數大於2次的記錄

--傳統方法(偏向於所有找出來)

select * from User_Register

where ID in

(

    select ID from User_Register

    group by ID having count(ID)>1

)

order by ID

   

--推薦方法(偏向於找多餘重複值)

select * from (select row_number() over(partition by ID order by ID) RId,* from User_Register) Temp

where RId>1

 

12. 圖書表(圖書號,圖書名,做者編號,出版社,出版日期)做者表(做者編號,做者姓名,年齡,性別)。用SQL語句查詢出年齡小於平均年齡的做者名稱、圖書名,出版社

select WriterName,BookName,PublishingHouse from Books

inner join Writer on Books.WriterNo=Writer.WriterNo

where Writer.Age < (select avg(Age) from Writer)

   

13. 返回num最小的記錄(禁止使用min,max等統計函數)

select top 1 * from TestNums

where num is not null

order by num 

 

14. 舉例說下項目中視圖的好處?

項目裏面通常把一些業務比較複雜的東西封裝在一個視圖裏面,好比說項目裏面這個查詢用到了10多張表,表與表之間的關係邏輯你都得搞清楚,後期維護的時候又要拿出來弄懂,太浪費時間了,這時候視圖的做用就突襲出了 

 

15. SQLServer有哪些系統數據庫?分別是幹什麼的?

Master,系統用的一些表、存儲過程

Tempdb,臨時表存放的數據庫

Msdb,定時任務存放的系統數據庫

Model,數據庫模版,新建數據庫的時候,他會把Model裏面的東西拷貝一份到新的數據庫裏面

eg:(其實不止這些系統表,這些是比較經常使用的)

   

 

16. 索引有什麼好處,又有何缺點?彙集索引和非彙集索引有什麼區別?

索引都是爲了提升查詢速度的,索引通常添加到不是頻繁改動的字段上。

 

索引也是佔空間滴,查詢速度是快了增刪改可就慢咯~

彙集索引影響排序,非彙集索引不影響排序。(主鍵默認是彙集索引哦)

彙集索引是主鍵時候的排序是這個樣子的:

彙集索引改爲Title01

默認排序就以Title01爲準了

 

17. 何時須要SQLServer發郵件?怎麼去發郵件(只要求掌握圖形化頁面,命令會使用便可)?

這個應用案例不少,通常都是預警,好比異常鏈接的時候,或者數據庫報錯的時候,通常都會和定時任務聯合使用。

 

發郵件相關介紹:http://www.cnblogs.com/dunitian/p/6022826.html

簡單說下:

在配置以前請先把郵件的POP3之類的設置一下:

 圖形化演示: 

配置名字隨意取,能夠用項目名。顯示名稱建議用版本號+服務器ip,這樣出問題能夠定位跟蹤

   

 微軟圖形化的東西通常有個特色,一路下一步基本上能解決全部基礎問題

勾選一下(貌似不勾選也沒事)

測試一下:

發一封郵件到"我爲NET狂"的官方郵件去

去看看:

命令演示:(不須要記,你又不是DBA,會用便可)

 

 

發送郵件腳本:

1
2
3
4
5
6

exec msdb.dbo.sp_send_dbmail
@profile_name = 'SQLServer_DotNetCrazy1', --配置名稱
@recipients = 'dotnetcrazy@foxmail.com', --收件名稱
@body_format = 'HTML', --內容格式
@subject = '文章標題',
@body = '郵件內容'

結果:20的ip也發過來了

--相關查詢

--select * from msdb.dbo.sysmail_allitems

--select * from msdb.dbo.sysmail_faileditems --失敗狀態的消息

--select * from msdb.dbo.sysmail_unsentitems --看未發送的消息

--select * from msdb.dbo.sysmail_sentitems --查看已發送的消息

--select * from msdb.dbo.sysmail_event_log --記錄日記 

 

18. 存儲過程有什麼優勢?又有哪些缺點?

存儲過程執行效率高。1.傳輸的字節少響應也就快了嘛;2.存儲過程建立的時候已經預編譯好了,運行時直接進行執行計劃,而傳統的sql腳本得先生成執行計劃再執行。3.SQL注入防禦

 

擴展不方便,好比數據庫是複合的Nosql+MSSQL,代碼修改業務更方便。存儲過程裏面的SQL就不適合了(你SQLServer的腳本總不能和其餘NoSQL的通用吧),得抽出來用代碼實現。 

 

19. 數據庫TestStudent中學生表用到了TestMain中的Class表。

①請查詢一下TestStudent中的學生在哪一個班級?

一個服務器,多個數據庫

--跨數據庫查詢

select SId,SName,CName from [TestStudent].[dbo].[StudentInfo] as Student

inner join [TestMain].[dbo].[Class] as Class on Student.SClassId=Class.CId

go

 

--多個服務器,多個數據庫

--先連接服務器

 

 

--跨數據庫查詢

select SId,SName,CName from [q***257691.my3w.com].[q***257691_db].[dbo].[StudentInfo] as Student

inner join [TestMain].[dbo].[Class] as Class on Student.SClassId=Class.CId

go

 

②思考一下要是我修改了TestMain的數據庫名如何避免再次去批量修改SQL?

一個服務器,多個數據庫

--要是我手動改了數據庫名或者表名豈不歇菜?全部就有了同義詞

use TestMain

if(exists(select * from sys.synonyms where name='TestMainClass'))

    drop synonym TestMainClass

create synonym TestMainClass for [TestMain].[dbo].[Class]

   

if(exists(select * from  sys.synonyms where name='TestStudentInfo'))

    drop synonym TestStudentInfo

create synonym TestStudentInfo for [TestStudent].[dbo].[StudentInfo]

   

--跨數據庫查詢

use TestMain

select SId,SName,CName from TestStudentInfo as Student

inner join TestMainClass as Class on Student.SClassId=Class.CId

go

 

 

--多個服務器,多個數據庫

--先連接服務器,再同義詞

--要是我手動改了數據庫名或者表名豈不歇菜?全部就有了同義詞

use TestMain

if(exists(select * from sys.synonyms where name='TestMainClass'))

    drop synonym TestMainClass

create synonym TestMainClass for [TestMain].[dbo].[Class]

   

if(exists(select * from  sys.synonyms where name='TestStudentInfo'))

    drop synonym TestStudentInfo

create synonym TestStudentInfo for [q***257691.my3w.com].[q***257691_db].[dbo].[StudentInfo]

   

--跨數據庫查詢

use TestMain

select SId,SName,CName from TestStudentInfo as Student

inner join TestMainClass as Class on Student.SClassId=Class.CId

go

 

20. 針對索引缺點,項目中咱們通常怎麼解決?

讀寫分離(發佈訂閱)

讀庫創建索引,寫庫不創建索引 

 

簡單演示一下發布訂閱,具體的能夠自行研究:

發佈:

訂閱:

數據同步問題就不用你操心了

 

21. 隨着業務的發展,大家數據庫層面是怎麼逐步處理的?(我之前在羣裏也系統的說過,這個主要考察你是否真正參與一次頗具規模的完整項目中,不必定長篇大論,說你知道的就好了)

先聲明一些,若是有什麼錯誤歡迎反饋,畢竟這個下面的東西都是逆天本身慢慢摸索的,並無人指導,因此不免會出錯~~~(仍是先說下的好,否則有些不肯意分享的人會揪着小問題說啥誤人子弟。PS:逆天寧願別人也這樣誤誤我,本身搗鼓說出來都是淚啊!)

 

一開始是數據量慢慢大了查詢特別慢,因而在不常常修改又常用的列創建了索引,等差很少表裏有100w左右的數據了,開始有點吃不消了,因而就有了分表技術。分表技術不少,hashcode取餘,路由表等等。。。剛開始就是僞分表,也就是傳說中的水平分表,仍是在一個數據庫裏面,主要目的就是爲了解決ID溢出或者單個表數據太多而致使查詢太慢 

 

後來仍是有點吃不消,總不能由於某個表而影響總體性能吧,因而就把這個特別影響數據庫總體性能的表拎出來,放到另外的數據庫裏面,這個就是分庫技術,把一些影響總體性能的表單獨放到其餘數據庫裏面叫作垂直分庫,由於不在同一個數據庫了,也就能夠不放在一個盤裏面了,大大化解了IO的壓力。後來衍生出了垂直分表的概念(把某些分表放在其餘庫裏面,這時候路由表的表名就得寫全了)。

(擴:水平分庫http://www.cnblogs.com/dunitian/p/5276431.html)

 

舉了個簡單的例子:

後來系統繼續用繼續用,發現...又不給力了,這時候是服務器瓶頸了(網絡,IO,鏈接數,CPU,內存等硬件瓶頸),這時候所謂的本機垂直分庫就意義不大了,就有了分佈式的概念,分佈式分佈式,也就是單機變成多機器嘛,這時候sql上遇到各類問題,爲了解決這些問題引入了同義詞連接服務器的概念(19題考察的就是這個),這下覺得沒啥事情了,發現...什麼狀況,增刪改各類慢?查詢卻是還行。

 

細細研究發現,我去,是索引的問題(16,20題考察的內容)。而後借鑑MySQL的相關概念,他們每天說什麼讀寫分離,那麼咱們是否是也能夠走一個呢?因而就搞了多個庫,2個讀1個寫。這時候想到一個問題!數據同步怎麼辦?數據怎麼保證一致性?!!!

 

因而就有了發佈訂閱(這個裏面又有兩種,一種是主數據庫一改變就推送給從數據庫,一種是從數據庫按期向主數據庫發起同步請求【效率低】)這種讀寫分離,主數據庫進行增刪改,2個從數據庫只用來查,只給新手讀庫的權限,不再用擔憂他們修改不加where了~

 

後來就是業務問題了,我點,我點,我再點~我去,報了一個莫名的錯誤怎麼辦?

靠,是誰刪了這條數據!怎麼知道?

靠,磁盤快滿了,怎麼沒人說?!!

不用擔憂==》引入數據庫異常預警的功能(XEVENT+數據庫發郵件)【這個是站在前人肩上的成果】

 

如今:集羣怎麼搞?故障轉移怎麼走起?逆天正在研究中........

 

若是通過上面優化並且數據庫數據不算大(百G左右吧),那麼能夠得出個結論==》代碼太爛,重構去,二期走起~

 

22. 設計題:請根據如下圖設計一下商品相關的簡表(不包含活動、訂單、運費等)

a.    畫出設計圖【主要考察是否有必定的真實項目經歷】

b.    寫出建庫建表語句(每一個表數據很多於3個)【主要考察SQL基礎】

   

   

   

   

   

 建庫大家就本身慢慢建吧,我簡單設計了一個模型:(有不合理的設計歡迎提出

相關文章
相關標籤/搜索