☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
資料庫 中級

MSSQL 特有功能

SQL Server Management Studio(SSMS)

SSMS 是管理 SQL Server 的圖形化工具,就像 Visual Studio 之於 C#,SSMS 之於 SQL Server。

常用功能

  • 物件總管:瀏覽資料庫、資料表、索引等
  • 查詢編輯器:撰寫和執行 SQL
  • 執行計畫:圖形化顯示查詢效能
  • 活動監視器:監控伺服器狀態
-- 在 SSMS 中常用的查詢
-- 查看所有資料庫
SELECT name FROM sys.databases;            -- 列出所有資料庫名稱

-- 查看某個資料庫的所有資料表
SELECT TABLE_NAME                          -- 選取資料表名稱
FROM INFORMATION_SCHEMA.TABLES             -- 從資訊架構表
WHERE TABLE_TYPE = 'BASE TABLE';           -- 只要基本資料表(排除 View)

-- 查看資料表的欄位資訊
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE -- 選取欄位名、資料型別、是否可為空
FROM INFORMATION_SCHEMA.COLUMNS            -- 從欄位資訊表
WHERE TABLE_NAME = 'Students';             -- 指定資料表名稱

Stored Procedures(預存程序)

預存程序是預先編譯並儲存在資料庫中的 SQL 程式

想像一道菜的食譜:你把做菜步驟寫好存起來(CREATE PROCEDURE),之後只要說一聲「做這道菜」(EXEC),就會自動按步驟執行。

-- 建立預存程序:查詢學生成績報表
CREATE PROCEDURE sp_GetStudentReport       -- 建立名為 sp_GetStudentReport 的預存程序
    @MinScore INT = 60,                    -- 參數:最低分數(預設 60)
    @CourseName NVARCHAR(100) = NULL       -- 參數:課程名稱(可選)
AS
BEGIN
    SET NOCOUNT ON;                        -- 不回傳「受影響的列數」訊息

    SELECT                                 -- 查詢學生成績報表
        s.Name AS StudentName,             -- 學生姓名
        c.CourseName,                      -- 課程名稱
        e.Score,                           -- 分數
        CASE                               -- 用 CASE 判斷等級
            WHEN e.Score >= 90 THEN N'優秀' -- 90 分以上
            WHEN e.Score >= 80 THEN N'良好' -- 80~89 分
            WHEN e.Score >= 60 THEN N'及格' -- 60~79 分
            ELSE N'不及格'                  -- 60 分以下
        END AS Grade                       -- 等級欄位
    FROM Students s                        -- 從學生表
    JOIN Enrollments e ON s.Id = e.StudentId -- 連接選課表
    JOIN Courses c ON e.CourseId = c.Id       -- 連接課程表
    WHERE e.Score >= @MinScore             -- 篩選分數
        AND (@CourseName IS NULL OR c.CourseName = @CourseName) -- 可選的課程篩選
    ORDER BY e.Score DESC;                 -- 依分數降序排列
END;
-- 執行預存程序
EXEC sp_GetStudentReport;                  -- 使用預設參數
EXEC sp_GetStudentReport @MinScore = 80;   -- 只看 80 分以上
EXEC sp_GetStudentReport @MinScore = 70, @CourseName = N'C# 程式設計'; -- 指定兩個參數
// 在 Dapper 中呼叫預存程序
var results = await conn.QueryAsync<StudentReport>( // 用 Dapper 查詢
    "sp_GetStudentReport",               // 預存程序名稱
    new { MinScore = 80 },                 // 傳入參數
    commandType: CommandType.StoredProcedure // 指定為預存程序
);

// 在 EF Core 中呼叫預存程序
var results = await db.Students            // 使用 EF Core
    .FromSqlRaw("EXEC sp_GetStudentReport @p0, @p1", 80, "C#") // 呼叫預存程序
    .ToListAsync();                        // 取得結果

Views(檢視)

View 是預先定義好的查詢,用起來像一張虛擬的資料表。

-- 建立 View:學生成績摘要
CREATE VIEW vw_StudentSummary AS           -- 建立名為 vw_StudentSummary 的 View
SELECT                                     -- 查詢內容
    s.Id AS StudentId,                     -- 學生 ID
    s.Name AS StudentName,                 -- 學生姓名
    COUNT(e.Id) AS CourseCount,            -- 選課數量
    AVG(e.Score) AS AvgScore,              -- 平均分數
    MAX(e.Score) AS HighestScore           -- 最高分數
FROM Students s                            -- 從學生表
LEFT JOIN Enrollments e                    -- 左連接選課表
    ON s.Id = e.StudentId                  -- 連接條件
GROUP BY s.Id, s.Name;                     -- 依學生分組
-- 使用 View(就像查資料表一樣)
SELECT * FROM vw_StudentSummary            -- 查詢 View
WHERE AvgScore >= 80                       -- 篩選平均 80 分以上
ORDER BY AvgScore DESC;                    -- 依平均分數排序

Functions(使用者定義函數)

-- 純量函數(回傳單一值)
CREATE FUNCTION fn_GetLetterGrade          -- 建立計算等級的函數
(
    @Score INT                             -- 參數:分數
)
RETURNS NVARCHAR(10)                       -- 回傳型別:字串
AS
BEGIN
    RETURN CASE                            -- 判斷等級
        WHEN @Score >= 90 THEN N'A'        -- 90 分以上
        WHEN @Score >= 80 THEN N'B'        -- 80~89 分
        WHEN @Score >= 70 THEN N'C'        -- 70~79 分
        WHEN @Score >= 60 THEN N'D'        -- 60~69 分
        ELSE N'F'                          -- 60 分以下
    END;
END;
-- 使用函數
SELECT Name, Score,                        -- 選取姓名和分數
    dbo.fn_GetLetterGrade(Score) AS Grade   -- 呼叫函數計算等級
FROM Students;                             -- 從學生表查詢

Triggers(觸發器)

⚠️ 觸發器很強大但也很危險——它們會在特定操作時自動觸發,如果不小心可能造成意想不到的副作用。

-- 建立觸發器:記錄學生資料的修改歷史
CREATE TRIGGER trg_StudentAudit            -- 建立觸發器
ON Students                                -- 綁定在 Students 表上
AFTER UPDATE                               -- 在 UPDATE 之後觸發
AS
BEGIN
    SET NOCOUNT ON;                        -- 不回傳影響列數

    INSERT INTO StudentAuditLog            -- 寫入審計日誌表
    (
        StudentId,                         -- 學生 ID
        OldName,                           -- 修改前的姓名
        NewName,                           -- 修改後的姓名
        ChangedAt                          -- 修改時間
    )
    SELECT                                 -- 從 inserted 和 deleted 虛擬表取值
        i.Id,                              -- 學生 ID
        d.Name,                            -- deleted 表 = 修改前的值
        i.Name,                            -- inserted 表 = 修改後的值
        GETDATE()                          -- 目前時間
    FROM inserted i                        -- inserted = 新值
    JOIN deleted d ON i.Id = d.Id;         -- deleted = 舊值
END;

💡 為什麼要小心觸發器?

  • 觸發器是「隱形」的——看程式碼看不到它會執行
  • 可能造成連鎖觸發(觸發器 A 觸發觸發器 B)
  • 偵錯困難,效能影響不容易發現
  • 建議:優先使用應用程式邏輯或 EF Core 的 SaveChanges 事件

SQL Server Profiler 基礎

SQL Server Profiler 用來監控資料庫的即時活動

常見用途

  • 找出慢查詢(Slow Query)
  • 監控哪些 SQL 被執行
  • 偵錯效能問題
-- 替代方案:用 DMV(Dynamic Management Views)查詢效能資訊
-- 查看目前正在執行的查詢
SELECT                                     -- 查詢執行中的請求
    r.session_id,                          -- 連線 ID
    r.status,                              -- 狀態
    r.command,                             -- 命令類型
    t.text AS QueryText,                   -- SQL 文字
    r.total_elapsed_time / 1000 AS ElapsedSec -- 已執行秒數
FROM sys.dm_exec_requests r                -- 從執行請求 DMV
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t -- 取得 SQL 文字
WHERE r.session_id > 50;                   -- 排除系統連線
-- 查看最耗資源的查詢(Top 10)
SELECT TOP 10                              -- 取前 10 名
    qs.total_elapsed_time / qs.execution_count AS AvgTime, -- 平均執行時間
    qs.execution_count,                    -- 執行次數
    SUBSTRING(t.text, 1, 200) AS QueryText -- SQL 文字(前 200 字)
FROM sys.dm_exec_query_stats qs            -- 從查詢統計 DMV
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t -- 取得 SQL 文字
ORDER BY AvgTime DESC;                     -- 依平均時間降序

系統資料庫

資料庫 用途
master 系統級設定、登入帳號、所有資料庫的目錄
tempdb 暫存資料、臨時表、排序暫存(重啟後清空)
model 新資料庫的範本(新建 DB 會複製 model 的設定)
msdb SQL Agent 排程工作、備份歷史
-- 查看 tempdb 使用狀況
SELECT                                     -- 查詢 tempdb 空間使用
    SUM(unallocated_extent_page_count) * 8 / 1024 AS FreeSpaceMB,  -- 可用空間
    SUM(internal_object_reserved_page_count) * 8 / 1024 AS InternalMB, -- 內部物件
    SUM(user_object_reserved_page_count) * 8 / 1024 AS UserMB         -- 使用者物件
FROM sys.dm_db_file_space_usage;           -- 從空間使用 DMV 查詢

🤔 我這樣寫為什麼會錯?

❌ 錯誤 1:使用 Cursor(游標)代替集合操作

-- ❌ 用游標逐列處理(非常慢)
DECLARE @Id INT, @Score INT                -- 宣告變數
DECLARE student_cursor CURSOR FOR          -- 宣告游標
    SELECT Id, Score FROM Students         -- 游標查詢

OPEN student_cursor                        -- 開啟游標
FETCH NEXT FROM student_cursor INTO @Id, @Score -- 取得第一列

WHILE @@FETCH_STATUS = 0                   -- 迴圈處理每一列
BEGIN
    UPDATE Students SET Score = @Score + 5 -- 逐列更新
    WHERE Id = @Id                         -- 一次只更新一列
    FETCH NEXT FROM student_cursor INTO @Id, @Score -- 取下一列
END

CLOSE student_cursor                       -- 關閉游標
DEALLOCATE student_cursor                  -- 釋放游標
-- 逐列處理 → 超級慢!像是一個一個搬磚頭
-- ✅ 用集合操作一次搞定
UPDATE Students                            -- 一個 UPDATE 語句
SET Score = Score + 5;                     -- 一次更新所有列
-- 集合操作 → 超級快!像是開怪手一次搬一堆

❌ 錯誤 2:觸發器連鎖導致效能問題

-- ❌ 觸發器 A 修改表 B → 表 B 上的觸發器又修改表 C → ...
-- 造成連鎖反應,難以追蹤和偵錯
-- 而且可能導致無限迴圈!

-- ✅ 盡量用應用程式邏輯取代觸發器
-- 在 EF Core 的 SaveChanges 中處理審計邏輯

❌ 錯誤 3:直接修改系統資料庫

-- ❌ 絕對不要手動修改 master、tempdb 的資料
-- USE master
-- DELETE FROM sys.objects ... ← 不要這樣做!

-- ✅ 只使用官方提供的系統預存程序和 DDL 語句
-- 例如用 ALTER DATABASE 修改設定
-- 用 sp_helpdb 查看資料庫資訊
EXEC sp_helpdb;                            -- 查看所有資料庫的詳細資訊

💡 重點整理

概念 說明
Stored Procedure 預先編譯的 SQL 程式,可重複呼叫
View 虛擬資料表,簡化複雜查詢
Function 回傳值的 SQL 函數
Trigger 自動觸發的程式(小心使用)
DMV 動態管理檢視,監控效能
系統資料庫 master、tempdb、model、msdb

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊