面試準備(一)

@燈火闌珊發表於2020-11-21

面試準備(一)

談談你對ASP.NET底層原理的瞭解

​ 談到這個就不得不說說HTTP的請求處理流程了。作為一個程式設計師,你有沒有思考過為什麼在瀏覽器的位址列中輸入一個網址就能訪問到相應的頁面。類似於思考“為什麼蘋果往地上掉而不是往天上飄”,這種常識對於人們來說就好像是太陽天天東昇西落一樣被認為是理所當然的。但對於程式設計師來說,還是很有必要了解了解其底層原理的。事實上,當我們按下Enter鍵的那短暫的一刻,IIS和.Net Framework已經做了大量的幕後工作了。

​ 我們在開發過程中,常常會用到諸如HttpContext這樣的類,但我們有沒有想過這些類的構成和類的實體是如何建立的呢?回答類似這樣的問題,首先需要了解IIS是如何處理頁面請求的,這也是理解Form驗證模式和Windows驗證模式的基礎。

​ 當伺服器接收到一個Http請求的時候,IIS首先根據檔案的字尾名去處理這個請求(伺服器處理一個.html頁面和一個.aspx頁面肯定是不一樣的)。伺服器獲取所請求的頁面(或檔案)的字尾名以後,就會在伺服器端尋找可以處理這這類字尾名的應用程式,之後IIS將直接把這個檔案返還給客戶端。能夠處理各種字尾名的應用程式,通常被稱為ISAPI應用程式(網際網路伺服器應用程式介面:實際上只是一個介面,起到一個代理作用,主要工作是對映所請求的頁面或檔案和與此字尾名相對應的實際的處理程式。)

​ 從本質上講,Asp.Net 主要是由一系列的類組成,這些類的主要目的就是將Http請求轉變為對客戶端的響應。HttpRuntime類是Asp.Net的一個主要入口,它有一個稱作 ProcessRequest 的方法,這個方法以一個 HttpWorkerRequest 類作為引數。HttpRuntime 類幾乎包含著關於單個 Http請求的所有資訊:所請求的檔案、伺服器端變數、QueryString、Http 頭資訊 等等。Asp.Net 使用這些資訊來載入、執行正確的檔案,並且將這個請求轉換到輸出流中,一般來說,也就是HTML頁面。(二般來說,也可以是圖片)

談談你對.NET Core的瞭解

​ ASP.NET Core 是一個全新的開源、跨平臺框架,可以用它來構建基於網路連線的現代雲應用程式,比如:Web 應用,IoT(Internet Of Things,物聯網)應用和移動後端等。ASP.NET Core可以執行在 .NET Core 或完整的 .NET Framework 之上,其架構為釋出到雲端或本地執行的應用提供了一個最佳的開發框架,由開銷很小的模組化元件構成,這就保持了你構造解決方案的靈活性。你可以跨平臺地在Windows、Mac和Linux等裝置上開發和執行你的 ASP.NET Core 應用。ASP.NET Core 的原始碼已經在 GitHub 上託管。

什麼是儲存過程

​ 儲存過程(Procedure)是一組為了完成特定功能的SQL語句集合,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名稱並給出引數來執行。儲存過程可以包含邏輯控制語句和資料操縱語句,可以接受輸入引數、輸出引數、返回單個或多個結果集以及返回值。

儲存過程的優點?

  1. 減少網路通訊量。呼叫一個行數不多的儲存過程與直接呼叫SQL語句的網路通訊量可能不會有很大的差別,可是如果儲存過程包含上百行SQL語句,那麼其效能絕對比一條一條的呼叫SQL語句要高得多。
  2. 執行速度更快。有兩個原因:首先,在儲存過程建立的時候,資料庫已經對其進行了一次解析和優化。其次,儲存過程一旦執行,在記憶體中就會保留一份這個儲存過程,這樣下次再執行同樣的儲存過程時,可以從記憶體中直接呼叫。
  3. 更強的適應性:由於儲存過程對資料庫的訪問是通過儲存過程來進行的,因此資料庫開發人員可以在不改動儲存過程介面的情況下對資料庫進行任何改動,而這些改動不會對應用程式造成影響。
  4. 布式工作:應用程式和資料庫的編碼工作可以分別獨立進行,而不會相互壓制。
  5. 安全性高,可設定只有某此使用者才具有對指定儲存過程的使用權。

儲存過程的缺點?

  1. 儲存過程對應於專門的資料庫,可移植性差;
  2. 儲存過程需要專門的DBA編寫;
  3. 儲存過程容易混合業務邏輯,導致整個儲存過程變得複雜和難以維護;

儲存過程的分類

​ 根據返回值型別的不同,我們可以將儲存過程分為三類:

  • 返回記錄集的儲存過程:返回記錄集的儲存過程的執行結果是一個記錄集,典型的例子是從資料庫中檢索出符合某一個或幾個條件的記錄;

  • 返回數值的儲存過程(也可以稱為標量儲存過程):返回數值的儲存過程執行完以後返回一個值,例如在資料庫中執行一個有返回值的函式或命令;

  • 以及行為儲存過程:行為儲存過程僅僅是用來實現資料庫的某個功能,而沒有返回值,例如在資料庫中的更新和刪除操作。

什麼是系統儲存過程?

​ 系統儲存過程是系統建立的儲存過程,目的在於能夠方便的從系統表中查詢資訊或完成與更新資料庫表相關的管理任務或其他的系統管理任務。系統儲存過程主要儲存在master資料庫中,以“sp”下劃線開頭的儲存過程。儘管這些系統儲存過程在master資料庫中,但我們在其他資料庫還是可以呼叫系統儲存過程。有一些系統儲存過程會在建立新的資料庫的時候被自動建立在當前資料庫中。

常見的系統儲存過程有哪些?

exec sp_databases; --檢視資料庫
exec sp_tables;        --檢視錶
exec sp_columns student;--檢視列
exec sp_helpIndex student;--檢視索引
exec sp_helpConstraint student;--約束
exec sp_stored_procedures;
exec sp_helptext 'sp_stored_procedures';--檢視儲存過程建立、定義語句
exec sp_rename student, stuInfo;--修改表、索引、列的名稱
exec sp_renamedb myTempDB, myDB;--更改資料庫名稱
exec sp_defaultdb 'master', 'myDB';--更改登入名的預設資料庫
exec sp_helpdb;--資料庫幫助,查詢資料庫資訊
exec sp_helpdb master;

系統儲存過程示例

--表重新命名
exec sp_rename 'stu', 'stud';
select * from stud;
--列重新命名
exec sp_rename 'stud.name', 'sName', 'column';
exec sp_help 'stud';
--重新命名索引
exec sp_rename N'student.idx_cid', N'idx_cidd', N'index';
exec sp_help 'student';

--查詢所有儲存過程
select * from sys.objects where type = 'P';
select * from sys.objects where type_desc like '%pro%' and name like 'sp%';

使用者自定義儲存過程

1、建立語法

create proc | procedure pro_name
    [{@引數資料型別} [=預設值] [output],
     {@引數資料型別} [=預設值] [output],
     ....
    ]
as
    SQL_statements

2、執行儲存過程與刪除儲存過程

​ 在未進入如何寫儲存過程的主體前,先介紹一下執行儲存過程和刪除儲存過程,這兩個操作應該是比較簡單的。

  • 執行儲存過程

{ EXECUTE | EXEC} proc_name [@pram=value [OUTPUT]]

​ 在帶引數的情況下,優先使用@parameter=value的形式。如果引數有預設值,並且傳入的也是預設值,則可以省略引數;如果引數是一個輸出引數,則需要攜帶OUTPUT關鍵字。

  • 刪除儲存過程

DROP PROCEDURE proc_name

3、建立不帶引數的儲存過程

--建立儲存過程
if (exists (select * from sys.objects where name = 'proc_get_student'))
    drop proc proc_get_student
go
create proc proc_get_student
as
    select * from student;

--呼叫、執行儲存過程
exec proc_get_student;

4、分支語句

​ 與其他開發語言類似,IF後面可以跟ELSE也可以不跟,可以有ELSE IF也可以沒有。同時需要注意一點的是,IF後只執行一塊程式碼,如果要執行多條語句,必須用BEGIN-END包裹起來。

IF @bookAble=1
        SET @bookName='SQL YES'    
ELSE
    BEGIN
        SET @bookName='SQL NO'
    END

5、迴圈語句

WHILE bool_expression
{ sql_statement | statement_block }
[ BREAK | CONTINUE ]


--迴圈例項
DECLARE @count INT;
SET @count = 1;

WHILE @count<10
BEGIN
    SET @count += 1
    PRINT @count
END

6、使用RETURN

​ RETURN語句可以立刻停止儲存過程的執行,任何位於RETURN語句之外的語句都不會被執行。在儲存過程結束的地方,實際上也是在邏輯上執行了一個RETURN,其返回的值為0,表示成功執行。與輸出引數的對比:輸出引數用於將資訊返回到呼叫儲存過程的程式碼中,並且它可以是任何資料型別。而RETURN只能返回整數值,通常用於表示成功或失敗。

7、修改儲存過程

--修改儲存過程
alter proc proc_get_student
as
select * from student;

8、建立帶引數的儲存過程

--帶參儲存過程
if (object_id('proc_find_stu', 'P') is not null)
    drop proc proc_find_stu
go
create proc proc_find_stu(@startId int, @endId int)
as
    select * from student where id between @startId and @endId
go

exec proc_find_stu 2, 4;

9、建立帶萬用字元引數的儲存過程

--帶萬用字元引數儲存過程
if (object_id('proc_findStudentByName', 'P') is not null)
    drop proc proc_findStudentByName
go
create proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%')
as
    select * from student where name like @name and name like @nextName;
go

exec proc_findStudentByName;
exec proc_findStudentByName '%o%', 't%';

10、建立帶輸出引數的儲存過程

if (object_id('proc_getStudentRecord', 'P') is not null)
    drop proc proc_getStudentRecord
go
create proc proc_getStudentRecord(
    @id int, --預設輸入引數
    @name varchar(20) out, --輸出引數
    @age varchar(20) output--輸入輸出引數
)
as
    select @name = name, @age = age  from student where id = @id and sex = @age;
go

-- 
declare @id int,
        @name varchar(20),
        @temp varchar(20);
set @id = 7; 
set @temp = 1;
exec proc_getStudentRecord @id, @name out, @temp output;
select @name, @temp;
print @name + '#' + @temp;

11、不快取儲存過程

--WITH RECOMPILE 不快取
if (object_id('proc_temp', 'P') is not null)
    drop proc proc_temp
go
create proc proc_temp
with recompile
as
    select * from student;
go

exec proc_temp;

12、加密儲存過程

--加密WITH ENCRYPTION 
if (object_id('proc_temp_encryption', 'P') is not null)
    drop proc proc_temp_encryption
go
create proc proc_temp_encryption
with encryption
as
    select * from student;
go

exec proc_temp_encryption;
exec sp_helptext 'proc_temp';
exec sp_helptext 'proc_temp_encryption';

13、帶遊標引數的儲存過程

if (object_id('proc_cursor', 'P') is not null)
    drop proc proc_cursor
go
create proc proc_cursor
    @cur cursor varying output
as
    set @cur = cursor forward_only static for
    select id, name, age from student;
    open @cur;
go
--呼叫
declare @exec_cur cursor;
declare @id int,
        @name varchar(20),
        @age int;
exec proc_cursor @cur = @exec_cur output;--呼叫儲存過程
fetch next from @exec_cur into @id, @name, @age;
while (@@fetch_status = 0)
begin
    fetch next from @exec_cur into @id, @name, @age;
    print 'id: ' + convert(varchar, @id) + ', name: ' + @name + ', age: ' + convert(char, @age);
end
close @exec_cur;
deallocate @exec_cur;--刪除遊標

14、分頁儲存過程

---儲存過程、row_number完成分頁
if (object_id('pro_page', 'P') is not null)
    drop proc proc_cursor
go
create proc pro_page
    @startIndex int,
    @endIndex int
as
    select count(*) from product
;    
    select * from (
        select row_number() over(order by pid) as rowId, * from product 
    ) temp
    where temp.rowId between @startIndex and @endIndex
go
--drop proc pro_page
exec pro_page 1, 4
--
--分頁儲存過程
if (object_id('pro_page', 'P') is not null)
    drop proc pro_stu
go
create procedure pro_stu(
    @pageIndex int,
    @pageSize int
)
as
    declare @startRow int, @endRow int
    set @startRow = (@pageIndex - 1) * @pageSize +1
    set @endRow = @startRow + @pageSize -1
    select * from (
        select *, row_number() over (order by id asc) as number from student 
    ) t
    where t.number between @startRow and @endRow;

exec pro_stu 2, 2;

Raiserror

​ Raiserror返回使用者定義的錯誤資訊,可以指定嚴重級別,設定系統變數記錄所發生的錯誤。

語法如下:

Raiserror({msg_id | msg_str | @local_variable}
  {, severity, state}
  [,argument[,…n]]
  [with option[,…n]]
)
  • # msg_id:在sysmessages系統表中指定的使用者定義錯誤資訊

  • # msg_str:使用者定義的資訊,資訊最大長度在2047個字元。

  • # severity:使用者定義與該訊息關聯的嚴重級別。當使用msg_id引發使用sp_addmessage建立的使用者定義訊息時,raiserror上指定嚴重性將覆蓋sp_addmessage中定義的嚴重性。

  • 任何使用者可以指定0-18直接的嚴重級別。只有sysadmin固定伺服器角色常用或具有alter trace許可權的使用者才能指定19-25直接的嚴重級別。19-25之間的安全級別需要使用with log選項。

  • # state:介於1至127直接的任何整數。State預設值是1。

raiserror('is error', 16, 1);
select * from sys.messages;
--使用sysmessages中定義的訊息
raiserror(33003, 16, 1);
raiserror(33006, 16, 1);

簡單圖書管理系統儲存過程例項

簡單圖書館管理系統示例

--簡單圖書館管理系統

--建立reader表
CREATE TABLE reader
(
    reader_id INT IDENTITY(1,1) NOT NULL,
    reader_email VARCHAR(120) NOT NULL,
    reader_name NVARCHAR(16) NULL,
    reader_password VARCHAR(16) NOT NULL,
    reader_enable BIT DEFAULT(1) NOT NULL,
    PRIMARY KEY(reader_id)
)
--建立book表
CREATE TABLE book
(
    book_id INT IDENTITY(1,1) NOT NULL,
    book_name NVARCHAR(50) NOT NULL,
    book_stock INT NOT NULL,                --書的庫存
    book_borrowed INT DEFAULT(0) NOT NULL,    --書的已借出數量
    book_enable BIT DEFAULT(1) NOT NULL,     
    CHECK (book_stock>=0),
    CHECK (book_borrowed>=0),
    CHECK (book_borrowed <= book_stock),
    PRIMARY KEY(book_id)
)
--建立borrow表
CREATE TABLE borrow
(
    borrow_id INT IDENTITY(1,1) NOT NULL,
    book_id INT NOT NULL,
    reader_id INT NOT NULL,
    borrow_start_date SMALLDATETIME NOT NULL,    --借閱開始日期
    borrow_end_date SMALLDATETIME NOT NULL,        --借閱歸還日期
    borrow_is_returned BIT DEFAULT(0) NOT NULL,    --歸還標記
    CHECK(borrow_start_date <=borrow_end_date),
    PRIMARY KEY(borrow_id),
    FOREIGN KEY(book_id) REFERENCES book(book_id),
    FOREIGN KEY(reader_id) REFERENCES reader(reader_id)
)



--增加書籍儲存過程
CREATE PROC proc_book_add
(
    @book_id INT OUTPUT,
    @book_name NVARCHAR(50),
    @book_stock INT 
)
AS

BEGIN
    SET NOCOUNT ON;
    INSERT INTO book (book_name,book_stock) VALUES (@book_name,@book_stock)
    --返回生成的唯一ID號
    SET @book_id=SCOPE_IDENTITY();
END




--檢查某本書是否有庫存
CREATE PROC proc_book_has_stock
(
    @book_id INT,
    @has_stock BIT OUTPUT
)
AS

BEGIN
    DECLARE @stockNum INT;
    DECLARE @borrowNum INT;
    SET NOCOUNT ON;
        
    SELECT @borrowNum=book_borrowed,@stockNum=book_stock FROM book WHERE book_id=@book_id;
    
    --比較是否有庫存
    IF (@stockNum > @borrowNum)
        SET @has_stock = 1
    ELSE
        SET @has_stock = 0
END




--借閱圖書
CREATE PROC proc_borrow_add
(
    @book_id INT,
    @reader_id INT,
    @borrow_start_date SMALLDATETIME,
    @borrow_end_date SMALLDATETIME
)
AS

BEGIN
    SET NOCOUNT ON;
    --設定事務處理
    BEGIN TRAN
        --更新圖書的借閱量+1
        UPDATE book SET book_borrowed=book_borrowed+1
        --插入一條圖書借閱資訊
        INSERT INTO borrow (book_id,reader_id,borrow_start_date,borrow_end_date) VALUES (@book_id,@reader_id,@borrow_start_date,@borrow_end_date)        
    COMMIT
END




--歸還圖書
CREATE PROC proc_borrow_return
(
    @borrow_id INT
)
AS

BEGIN
    DECLARE @bookId INT;
    SET NOCOUNT ON;
    --設定事務處理
    BEGIN TRAN
         --獲取book的唯一編號
         SELECT @bookId=book_id FROM borrow WHERE borrow_id=@borrow_id
         --更新borrow的歸還標記為1
         UPDATE borrow SET borrow_is_returned=1 WHERE borrow_id=@borrow_id
         --更新書的已借閱量-1
         UPDATE book SET book_borrowed=book_borrowed-1 WHERE book_id=@bookId
    COMMIT
END

關於儲存過程使用的爭論,我不傾向於儘可能使用儲存過程,個人認為:

  1. 執行速度: 大多數高階的資料庫系統都有statement cache的,所以編譯sql的花費沒什麼影響。但是執行儲存過程要比直接執行sql花費更多(檢查許可權等),所以對於很簡單的sql,儲存過程沒有什麼優勢。

  2. 網路負荷:如果在儲存過程中沒有多次資料互動,那麼實際上網路傳輸量和直接sql是一樣的。

  3. 團隊開發:很遺憾,比起成熟的IDE,沒有什麼很好儲存過程的IDE工具來支援,也就是說,這些必須手工完成。

  4. 安全機制:對於傳統的C/S結構,連線資料庫的使用者可以不同,所以安全機制有用;但是在web的三層架構中,資料庫使用者不是給使用者用的,所以基本上,只有一個使用者,擁有所有許可權(最多還有一個開發使用者)。這個時候,安全機制有點多餘。

  5. 使用者滿意:實際上這個只是要將訪問資料庫的介面統一,是用儲存過程,還是EJB,沒太大關係,也就是說,在三層結構中,單獨設計出一個資料訪問層,同樣能實現這個目標。

  6. 開發除錯:一樣由於IDE的問題,儲存過程的開發除錯要比一般程式困難(老版本DB2還只能用C寫儲存過程,更是一個災難)。

  7. 移植性:算了,這個不用提,反正一般的應用總是繫結某個資料庫的,不然就無法靠優化資料庫訪問來提高效能了。

  8. 維護性:的確,儲存過程有些時候比程式容易維護,這是因為可以實時更新DB端的儲存過程,但是在3層結構下,更新server端的資料訪問層一樣能實現這個目標,可惜現在很多平臺不支援實時更新而已。

    現在,我認為的原則是:所有資料訪問在應用層封裝為資料訪問層,在那裡,如果SQL簡單的話,直接用SQL;如果SQL複雜,或者資料互動多且中間資料最後不會用到,使用儲存過程。其他憑經驗吧。

事務處理

什麼是事務?

​ 事務是指做為單個邏輯工作單元的一系列操作,它保證成批的T-SQL操作要麼全部執行,要麼全部不執行。

事務的建立、提交、回滾、保留點

  • BEGIN TRAN[SACTION] [ tran_name ]

  • COMMIT [ TRAN[SACTION] tran_name ]

  • ROLLBACK [ TRAN[SACTION] tran_name ]

  • SAVE TRAN[SACTION] tran_name]

如何優化sql

  • 少用子查詢:儘量少用子查詢,因為子查詢會產生臨時表;除非像count(*)臨時表很小的。

  • 少用SELECT *:每次看到SELECT *都需要用懷疑的眼光審視,是否真的需要返回全部的列?取出全部的列,會讓優化器無法完成索引覆蓋掃描這類優化,還會為伺服器帶來額外的I/O、記憶體和CPU的消耗。

  • 查詢必要的記錄:一個常見的錯誤是常常會誤以為SQL Server只會返回需要的資料,實際上SQL Server卻是先返回全部結果集再進行計算,建議在查詢後面加上LIMIT。

  • 不要重複查詢相同的資料:不斷執行相同的查詢,然後每次都會返回完全相同的資料。可以採用的方案是初次查詢的時候將這個資料快取起來,需要的時候從快取中取出,這樣效能顯然會更好。

  • COUNT查詢優化:COUNT()聚合函式的作用: 統計某一個列值的數量,也可以統計行數。需要注意的是統計列值時要求列值是非空的(不統計NULL),COUNT()查詢儘可能少的行。

    舉個例子:如果我們直接查 id>100 的記錄,涉及到的有兩千多萬行記錄掃描。但是由於COUNT()特性,我們可以用 count() - (id<100)的做法,這樣掃描的行就只有100行了。

  • Where子句中,where表之間的連線必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾.HAVING最後。

  • 用EXISTS替代IN、用NOT EXISTS替代NOT IN。

  • 避免在索引列上使用計算。

  • 避免在索引列上使用IS NULL和IS NOT NULL。

  • 對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

  • 應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描。

  • 應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。

SQL Server索引

什麼是索引

​ 索引就是資料表中資料和相應的儲存位置的列表,利用索引可以提高在表或檢視中的查詢資料的速度。

索引分類

	資料庫中索引主要分為兩類:聚集索引和非聚集索引。SQL Server 2005還提供了唯一索引、索引檢視、全文索引、xml索引等等。聚集索引和非聚集索引是資料庫引擎中索引的基本型別,是理解其他型別索引的基礎。
  • 聚集索引是指表中資料行的物理儲存順序和索引的儲存順序完全相同。聚集索引根據索引順序物理地重新排列了使用者插入到表中的資料,因此,每個表只能建立一個聚集索引。聚集索引經常建立在表中經常被搜尋到的列或按順序訪問的列上。在預設情況下,主鍵約束自動建立聚集索引。
  • 非聚集索引不改變表中資料列的物理儲存位置,資料與索引分開儲存,通過索引指向的地址與表中的資料發生關係。非聚集索引沒有改變表中物理行的位置,索引可以在以下情況下使用非聚集索引:
    1. 如果某個欄位的資料唯一性比較高
    2. 如果查詢所得到的資料量比較少

聚集索引與非聚集索引的區別

聚集索引非聚集索引
每個表只允許建立一個聚集索引最多可以有249個非聚集索引
物理的重排表中的資料以符合索引約束建立一個鍵值列表,鍵值指向資料在資料頁中的位置
用於經常查詢資料的列用於從表中查詢單個值的列

其它型別索引

  • 唯一索引:如果希望索引鍵都不同,可以建立唯一索引。聚集索引和非聚集索引都可以是唯一索引。
  • 包含新列索引:索引列的最大數量是16個,索引列的位元組總數的最高值是900。如果當多個列的位元組總數大於900,切又想在這些劣種都包含索引是,可以使用包含性列索引
  • 檢視索引:提供檢視查詢效率,可以檢視的索引物理化,也就是說將結果集永久儲存在索引中,可以建立檢視索引。
  • XML索引:是與xml資料關聯的索引形式,是XML二進位制blob的已拆分持久表示形式
  • 全文索引:一種特殊型別的基於標記的功能性功能,用於幫助在字串中搜尋賦值的詞

建立索引

create [unique] [clustered | noclustered]
index index_name
on table_name (column_name ...)
[with fillfactor=x]

​ unique唯一索引、clustered聚集索引noclustered非聚集索引、fillfactor填充因子大小,範圍在0-100直接,表示索引頁填滿的空間所佔的百分比。

if (exists (select * from sys.indexes where name = 'idx_stu_name'))
    drop index student.idx_stu_name
go
create index idx_stu_name
on
student(name);
 
--聯合索引
if (exists (select * from sys.indexes where name = 'idx_uqe_clu_stu_name_age'))
    drop index student.idx_uqe_clu_stu_name_age
go
create unique clustered index idx_uqe_clu_stu_name_age
on student(name, age);
 
if (exists (select * from sys.indexes where name = 'idx_cid'))
    drop index student.idx_cid
go
 
if (exists (select * from sys.indexes where name = 'idx_cid'))
    drop index student.idx_cid
go
 
--非聚集索引
create nonclustered index idx_cid
on
student (cid)
with fillFactor = 30;    --填充因子
 
--聚集索引
if (exists (select * from sys.indexes where name = 'idx_sex'))
    drop index student.idx_sex
go
create clustered index idx_sex
on
student(sex);
 
--聚集索引
if (exists (select * from sys.indexes where name = 'idx_name'))
    drop index student.idx_name
go
create unique index idx_name
on
student(name);	
  • 適合的建立索引的列:當資料庫的某一列被頻繁的用於資料庫查詢時,或者該列用於資料庫進行排序時可以建立成索引

  • 不適合建立索引的列:如果列中有幾個不同的值,或者表中僅包含幾行值,則不推薦為其建立索引。因為索引在搜尋資料所花的時間比在表中逐行搜尋的時間更長

SQL Server檢視

檢視就是一個虛擬的資料表,該資料表中的資料記錄是有一條查詢語句的查詢結果得到的

建立檢視準則

  • 檢視名稱必須遵循識別符號的規則,該名稱不得與該架構的如何表的名稱相同

  • 你可以對其他檢視建立檢視。允許巢狀檢視,但巢狀不得超過32層。檢視最多可以有1024個欄位

  • 不能將規則和default定義於檢視相關聯

  • 檢視的查詢不能包含compute子句、compute by子句或into關鍵字

  • 定義檢視的查詢不能包含order by子句,除非在select 語句的選擇列表中還有top子句

下列情況必須指定檢視中每列的名稱:

  • 檢視中的如何列都是從算術表示式、內建函式或常量派生而來

  • 檢視中有兩列或多列具有相同名稱(通常由於檢視定義包含聯接,因此來自兩個或多個不同的列具有相同的名稱)

  • 希望檢視中的列指定一個與其原列不同的名稱(也可以在檢視中重新命名列)。無論是否重新命名,檢視列都會繼承原列的資料型別

建立檢視

if (exists (select * from sys.objects where name = 'v_stu'))
    drop view v_stu
go
create view v_stu
as
select id, name, age, sex from student;

修改檢視

alter view v_stu
as
select id, name, sex from student;
 
alter view v_stu(編號, 名稱, 性別)
as
    select id, name, sex from student
go
select * from v_stu;
 
select * from information_schema.views;

加密檢視

if (exists (select * from sys.objects where name = 'v_student_info'))
    drop view v_student_info
go
create view v_student_info
with encryption --加密
as
    select id, name, age from student
go
--view_definition is null
select * from information_schema.views 
where table_name like 'v_stu';

說一下你選擇這個行業的理由(行業前景)

​ 我覺得.NET大有前景,.NET憑藉其自身完整的框架結構以及微軟現在的各種開源,將在客戶端與Web服務以及大型企業級應用中能夠有更好的發展前景。隨著.NET5的誕生,今後就可能Web開發、桌面開發、移動開發、遊戲開發、物聯網開發、人工智慧、雲開發這幾大方向都能用.NET實現。

你個人的職業目標是什麼

​ 目前的話只能算是個初級開發工程師,所以先努力學習技術,努力工作,爭取一到兩年成長為中級開發工程師,努力工作幾年後往產品經理這個方向發展,因為感覺自己對產品的策劃會比較感興趣,也喜歡琢磨使用者體驗。之所以這樣選擇是因為對技術有了一定的瞭解後,當走向產品策劃的時候,對於產品的需求可能會更加貼切實際。

談談你對產品經理這個崗位的瞭解

​ 首先,產品經理並不意味著你不會再觸碰程式碼了。我喜歡與人探討分析、交流,在這一點上我覺得適合產品經理這個崗位。產品經理應該具備以下幾點能力:

  • 產品戰略和發展規劃的能力:比如說老闆要求公司在3年內要上市,那麼這個時候你就要圍繞如何推動公司上市來開發產品,這個產品的目標市場是什麼、目標使用者是什麼、盈利模式是什麼、你這個產品的獨有的特點和風格是什麼…。
  • 挖掘和分析需求的能力。
  • 推動產品目標實現的能力。
  • 較強的團隊合作和管理能力。

面試最後問的問題

  • 你在公司的一天一般是如何度過的?

  • 能否簡單介紹下貴公司的業務與未來的發展戰略

  • 貴公司最讓你自豪的企業文化是什麼?

  • 團隊、公司現在面臨的最大挑戰是什麼?

  • 對於未來加入這個團隊,你對我的期望是什麼?

  • 很好奇,你最不喜歡公司的哪一點?

  • 公司的組織架構是怎樣的?

  • 公司的發展控制元件及發展渠道

相關文章