最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SQL Server 字符集驗(yàn)證的實(shí)現(xiàn)

 更新時(shí)間:2026年03月19日 09:18:39   作者:喝醉酒的小白  
SQL Server 中的字符集和排序規(guī)則決定了數(shù)據(jù)如何存儲(chǔ)、比較和排序,理解字符集配置對(duì)數(shù)據(jù)庫的正常運(yùn)行至關(guān)重要,下面就來詳細(xì)的介紹一下SQL Server 字符集驗(yàn)證的實(shí)現(xiàn),感興趣的可以了解一下

文檔信息

項(xiàng)目內(nèi)容
文檔標(biāo)題SQL Server 實(shí)例與數(shù)據(jù)庫字符集不一致影響驗(yàn)證報(bào)告
測試環(huán)境mssql-1c247f8d
測試日期2026-03-13
文檔版本v1.0

一、字符集概述

1.1 SQL Server 字符集相關(guān)概念

SQL Server 中的字符集和排序規(guī)則(Collation)決定了數(shù)據(jù)如何存儲(chǔ)、比較和排序。理解字符集配置對(duì)數(shù)據(jù)庫的正常運(yùn)行至關(guān)重要。

概念說明
排序規(guī)則 (Collation)決定字符數(shù)據(jù)的排序、比較和存儲(chǔ)方式
排序規(guī)則名稱格式為 SQL_SortRules_Pref_CaseSensitivity_AccentSensitivity
實(shí)例級(jí)排序規(guī)則SQL Server 實(shí)例安裝時(shí)指定的默認(rèn)排序規(guī)則
數(shù)據(jù)庫級(jí)排序規(guī)則創(chuàng)建數(shù)據(jù)庫時(shí)指定的排序規(guī)則
列級(jí)排序規(guī)則創(chuàng)建列時(shí)指定的排序規(guī)則
表達(dá)式級(jí)排序規(guī)則查詢中可以指定特定的排序規(guī)則

1.2 排序規(guī)則命名規(guī)范

排序規(guī)則名稱格式示例:
Chinese_PRC_CI_AS
│       │   │  │
│       │   │  └─ KS: 寬度敏感 (Kana Sensitive)
│       │   └─ AI/AS: 重音不敏感/敏感 (Accent Insensitive/Sensitive)
│       └─ CI/CS: 大小寫不敏感/敏感 (Case Insensitive/Sensitive)
└─ 語言/地區(qū): Chinese_PRC, Latin1_General, SQL_Latin1 等
后綴說明
_CICase Insensitive - 大小寫不敏感
_CSCase Sensitive - 大小寫敏感
_AIAccent Insensitive - 重音不敏感
_ASAccent Sensitive - 重音敏感
_KIKana Insensitive - 假名不敏感
_KSKana Sensitive - 假名敏感
_WSWidth Sensitive - 寬度敏感
_BINBinary - 二進(jìn)制排序
_BIN2Binary2 - 二進(jìn)制排序(碼點(diǎn)比較)

二、查看當(dāng)前字符集配置

2.1 查看實(shí)例級(jí)排序規(guī)則

-- 方法1:查看服務(wù)器實(shí)例排序規(guī)則
SELECT SERVERPROPERTY('Collation') AS InstanceCollation;
GO

-- 方法2:通過系統(tǒng)數(shù)據(jù)庫查看
SELECT name, collation_name
FROM sys.databases
WHERE database_id <= 4;  -- 系統(tǒng)數(shù)據(jù)庫
GO

-- 方法3:查看數(shù)據(jù)庫默認(rèn)排序規(guī)則
SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS CurrentDBCollation;
GO

預(yù)期輸出示例:

InstanceCollation
Chinese_PRC_CI_AS

2.2 查看所有數(shù)據(jù)庫的排序規(guī)則

-- 查看所有數(shù)據(jù)庫的排序規(guī)則
SELECT
    database_id AS '數(shù)據(jù)庫ID',
    name AS '數(shù)據(jù)庫名稱',
    collation_name AS '排序規(guī)則',
    CASE
        WHEN collation_name = SERVERPROPERTY('Collation') THEN '與實(shí)例一致'
        ELSE '與實(shí)例不一致'
    END AS '狀態(tài)'
FROM sys.databases
ORDER BY database_id;
GO

2.3 查看列級(jí)別的排序規(guī)則

-- 查看特定表的列排序規(guī)則
SELECT
    t.name AS '表名',
    c.name AS '列名',
    ty.name AS '數(shù)據(jù)類型',
    c.max_length AS '最大長度',
    c.collation_name AS '排序規(guī)則',
    c.is_nullable AS '可空'
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types ty ON c.system_type_id = ty.system_type_id
WHERE t.type_desc = 'USER_TABLE'
  AND c.collation_name IS NOT NULL
ORDER BY t.name, c.column_id;
GO

2.4 查看支持的排序規(guī)則

-- 查看所有可用的排序規(guī)則
SELECT
    name AS '排序規(guī)則名稱',
    description AS '描述',
    COLLATIONPROPERTY(name, 'CodePage') AS '代碼頁'
FROM sys.fn_helpcollations()
WHERE name LIKE 'Chinese%'
   OR name LIKE 'SQL_Latin%'
ORDER BY name;
GO

三、字符集不一致的影響

3.1 主要影響概覽

影響類型說明嚴(yán)重程度
排序不一致跨庫 JOIN 時(shí)結(jié)果不正確
比較失敗跨庫數(shù)據(jù)比較時(shí)報(bào)錯(cuò)
性能下降需要隱式轉(zhuǎn)換導(dǎo)致性能下降
索引失效排序規(guī)則不同導(dǎo)致索引無法使用
字符轉(zhuǎn)換某些字符可能顯示為亂碼

3.2 詳細(xì)影響說明

影響 1:跨庫 JOIN 時(shí)報(bào)錯(cuò)

當(dāng)兩個(gè)數(shù)據(jù)庫使用不同的排序規(guī)則時(shí),直接進(jìn)行 JOIN 操作會(huì)報(bào)錯(cuò)。

-- 演示錯(cuò)誤:跨庫 JOIN 不同排序規(guī)則
-- 假設(shè) DB1 使用 Chinese_PRC_CI_AS
-- 假設(shè) DB2 使用 Chinese_PRC_CS_AS

USE DB1;
GO

SELECT a.id, b.name
FROM table_a a
INNER JOIN DB2.dbo.table_b b ON a.col1 = b.col1;  -- 這里會(huì)報(bào)錯(cuò)
GO

-- 錯(cuò)誤信息:
-- Msg 468, Level 16, State 9, Line 1
-- Cannot resolve the collation conflict between "Chinese_PRC_CI_AS" and "Chinese_PRC_CS_AS" in the equal to operation.

解決方案:

-- 方案1:使用 COLLATE 子句指定統(tǒng)一排序規(guī)則
SELECT a.id, b.name
FROM DB1.dbo.table_a a
INNER JOIN DB2.dbo.table_b b
    ON a.col1 COLLATE Chinese_PRC_CI_AS = b.col1 COLLATE Chinese_PRC_CI_AS;
GO

-- 方案2:使用數(shù)據(jù)庫默認(rèn)排序規(guī)則
SELECT a.id, b.name
FROM DB1.dbo.table_a a
INNER JOIN DB2.dbo.table_b b
    ON a.col1 = b.col1 COLLATE DATABASE_DEFAULT;
GO

影響 2:大小寫敏感問題

-- 實(shí)例級(jí)別排序規(guī)則:Chinese_PRC_CI_AS (大小寫不敏感)
-- 數(shù)據(jù)庫級(jí)別排序規(guī)則:Chinese_PRC_CS_AS (大小寫敏感)

-- 創(chuàng)建測試表
CREATE TABLE TestCase
(
    id INT,
    name NVARCHAR(50)
);
GO

-- 插入數(shù)據(jù)
INSERT INTO TestCase VALUES (1, 'abc');
INSERT INTO TestCase VALUES (2, 'ABC');
INSERT INTO TestCase VALUES (3, 'aBc');
GO

-- 在 Chinese_PRC_CI_AS (不敏感) 環(huán)境下
SELECT * FROM TestCase WHERE name = 'abc';
-- 返回 3 行:abc, ABC, aBc

-- 在 Chinese_PRC_CS_AS (敏感) 環(huán)境下
SELECT * FROM TestCase WHERE name = 'abc';
-- 返回 1 行:abc

影響 3:字符串比較問題

-- 不同排序規(guī)則下的字符串比較

-- 代碼頁不兼容可能導(dǎo)致的問題
DECLARE @var1 VARCHAR(50) COLLATE Chinese_PRC_CI_AS;
DECLARE @var2 VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS;

SET @var1 = '測試';
SET @var2 = '測試';

-- 直接比較會(huì)報(bào)錯(cuò)
IF @var1 = @var2
    PRINT 'Equal';
ELSE
    PRINT 'Not Equal';

-- 錯(cuò)誤信息:
-- Msg 468, Level 16, State 9, Line 3
-- Cannot resolve the collation conflict between "Chinese_PRC_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.

-- 解決方案:統(tǒng)一排序規(guī)則
IF @var1 COLLATE Chinese_PRC_CI_AS = @var2 COLLATE Chinese_PRC_CI_AS
    PRINT 'Equal';
ELSE
    PRINT 'Not Equal';

影響 4:索引使用問題

-- 創(chuàng)建測試表
CREATE TABLE TestIndex
(
    id INT PRIMARY KEY,
    col1 VARCHAR(50) COLLATE Chinese_PRC_CI_AS,
    col2 VARCHAR(50) COLLATE Chinese_PRC_CS_AS
);
GO

-- 創(chuàng)建索引
CREATE INDEX idx_col1 ON TestIndex(col1);
CREATE INDEX idx_col2 ON TestIndex(col2);
GO

-- 查詢時(shí)可能無法使用索引
SELECT * FROM TestIndex
WHERE col1 = 'test';  -- 可以使用索引

-- 如果與不同排序規(guī)則的列比較
SELECT * FROM TestIndex
WHERE col1 = col2 COLLATE Chinese_PRC_CS_AS;  -- 可能無法使用索引,導(dǎo)致掃描

四、字符集不一致的驗(yàn)證測試

4.1 測試場景 1:創(chuàng)建不同排序規(guī)則的數(shù)據(jù)庫

-- 查看當(dāng)前實(shí)例排序規(guī)則
DECLARE @InstanceCollation NVARCHAR(128);
SET @InstanceCollation = CAST(SERVERPROPERTY('Collation') AS NVARCHAR(128));
PRINT '實(shí)例排序規(guī)則: ' + @InstanceCollation;
GO

-- 創(chuàng)建與實(shí)例相同排序規(guī)則的數(shù)據(jù)庫
CREATE DATABASE TestDB_SameCollation
COLLATE Chinese_PRC_CI_AS;
GO

-- 創(chuàng)建與實(shí)例不同排序規(guī)則的數(shù)據(jù)庫
CREATE DATABASE TestDB_DiffCollation
COLLATE Chinese_PRC_CS_AS;
GO

-- 驗(yàn)證排序規(guī)則
SELECT
    name AS '數(shù)據(jù)庫名稱',
    collation_name AS '排序規(guī)則',
    CASE
        WHEN collation_name = SERVERPROPERTY('Collation') THEN '與實(shí)例一致'
        ELSE '與實(shí)例不一致'
    END AS '狀態(tài)'
FROM sys.databases
WHERE name IN ('TestDB_SameCollation', 'TestDB_DiffCollation');
GO

4.2 測試場景 2:跨庫 JOIN 測試

-- 在相同排序規(guī)則的數(shù)據(jù)庫中創(chuàng)建表
USE TestDB_SameCollation;
GO
CREATE TABLE TableA
(
    id INT IDENTITY PRIMARY KEY,
    code VARCHAR(20),
    name NVARCHAR(50)
);
GO
INSERT INTO TableA (code, name) VALUES ('A001', '名稱1'), ('A002', '名稱2');
GO

-- 在不同排序規(guī)則的數(shù)據(jù)庫中創(chuàng)建表
USE TestDB_DiffCollation;
GO
CREATE TABLE TableB
(
    id INT IDENTITY PRIMARY KEY,
    code VARCHAR(20),
    value INT
);
GO
INSERT INTO TableB (code, value) VALUES ('A001', 100), ('A003', 300);
GO

-- 測試跨庫 JOIN(會(huì)報(bào)錯(cuò))
USE TestDB_SameCollation;
GO
SELECT a.id, a.code, b.value
FROM TableA a
INNER JOIN TestDB_DiffCollation.dbo.TableB b ON a.code = b.code;
GO

-- 預(yù)期錯(cuò)誤:
-- Msg 468, Level 16, State 9
-- Cannot resolve the collation conflict between "Chinese_PRC_CI_AS" and "Chinese_PRC_CS_AS" in the equal to operation.

-- 正確的跨庫 JOIN 方式
SELECT a.id, a.code, b.value
FROM TableA a
INNER JOIN TestDB_DiffCollation.dbo.TableB b
    ON a.code COLLATE Chinese_PRC_CI_AS = b.code COLLATE Chinese_PRC_CI_AS;
GO

4.3 測試場景 3:臨時(shí)表排序規(guī)則

-- 臨時(shí)表使用 tempdb 的排序規(guī)則,可能與用戶數(shù)據(jù)庫不同

-- 查看當(dāng)前數(shù)據(jù)庫排序規(guī)則
SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS CurrentDBCollation;
GO

-- 查看 tempdb 排序規(guī)則
SELECT DATABASEPROPERTYEX('tempdb', 'Collation') AS TempDBCollation;
GO

-- 創(chuàng)建臨時(shí)表并測試
CREATE TABLE #TempTable
(
    id INT,
    code VARCHAR(20)
);
GO

-- 插入數(shù)據(jù)
INSERT INTO #TempTable VALUES (1, 'A001'), (2, 'A002');
GO

-- 創(chuàng)建用戶表
CREATE TABLE UserTable
(
    id INT,
    code VARCHAR(20)
);
GO
INSERT INTO UserTable VALUES (1, 'A001'), (2, 'A002');
GO

-- 如果排序規(guī)則不同,JOIN 可能失敗
SELECT t.id, u.code
FROM #TempTable t
INNER JOIN UserTable u ON t.code = u.code;
GO

-- 解決方案:明確指定排序規(guī)則
SELECT t.id, u.code
FROM #TempTable t
INNER JOIN UserTable u
    ON t.code COLLATE DATABASE_DEFAULT = u.code COLLATE DATABASE_DEFAULT;
GO

4.4 測試場景 4:字符串函數(shù)影響

-- 測試排序規(guī)則對(duì)字符串函數(shù)的影響

DECLARE @str1 VARCHAR(50) COLLATE Chinese_PRC_CI_AS;
DECLARE @str2 VARCHAR(50) COLLATE Chinese_PRC_CS_AS;

SET @str1 = 'TestString';
SET @str2 = 'teststring';

-- 大小寫敏感測試
SELECT
    CASE
        WHEN @str1 COLLATE Chinese_PRC_CI_AS = @str2 COLLATE Chinese_PRC_CI_AS
        THEN 'CI_AS: 相等'
        ELSE 'CI_AS: 不相等'
    END AS CI_Result,
    CASE
        WHEN @str1 COLLATE Chinese_PRC_CS_AS = @str2 COLLATE Chinese_PRC_CS_AS
        THEN 'CS_AS: 相等'
        ELSE 'CS_AS: 不相等'
    END AS CS_Result;
GO

-- 排序測試
SELECT
    'a' AS Char1,
    'A' AS Char2,
    CASE
        WHEN 'a' COLLATE Chinese_PRC_CI_AS < 'A' COLLATE Chinese_PRC_CI_AS
        THEN 'a < A (CI)'
        ELSE 'a >= A (CI)'
    END AS CI_Sort,
    CASE
        WHEN 'a' COLLATE Chinese_PRC_CS_AS < 'A' COLLATE Chinese_PRC_CS_AS
        THEN 'a < A (CS)'
        ELSE 'a >= A (CS)'
    END AS CS_Sort;
GO

五、常見排序規(guī)則對(duì)比

5.1 中文排序規(guī)則對(duì)比

排序規(guī)則說明代碼頁大小寫敏感重音敏感適用場景
Chinese_PRC_CI_AS簡體中文,不區(qū)分大小寫936最常用,推薦
Chinese_PRC_CS_AS簡體中文,區(qū)分大小寫936需要區(qū)分大小寫
Chinese_PRC_BIN簡體中文,二進(jìn)制排序936精確匹配場景
Chinese_Taiwan_CI_AS繁體中文,不區(qū)分大小寫950臺(tái)灣地區(qū)
Chinese_Hong_Kong_CI_AS香港繁體,不區(qū)分大小寫950香港地區(qū)

5.2 排序規(guī)則選擇建議

應(yīng)用場景推薦排序規(guī)則理由
中文通用應(yīng)用Chinese_PRC_CI_AS大小寫不敏感,符合用戶習(xí)慣
密碼/敏感數(shù)據(jù)Chinese_PRC_CS_AS 或 Chinese_PRC_BIN大小寫敏感,安全性高
多語言環(huán)境Latin1_General_CI_AS支持多語言
國際化應(yīng)用SQL_Latin1_General_CP1_CI_ASSQL Server 默認(rèn),兼容性好

六、字符集不一致的解決方案

6.1 解決方案 1:統(tǒng)一排序規(guī)則(推薦)

-- 方案1:重建數(shù)據(jù)庫為統(tǒng)一排序規(guī)則

-- 步驟1:備份數(shù)據(jù)庫
BACKUP DATABASE TestDB_DiffCollation
TO DISK = 'C:\Backup\TestDB_DiffCollation.bak';
GO

-- 步驟2:導(dǎo)出所有數(shù)據(jù)和對(duì)象
-- 使用 SQL Server Management Studio 的生成腳本功能
-- 或使用 bcp 命令導(dǎo)出數(shù)據(jù)

-- 步驟3:刪除數(shù)據(jù)庫
DROP DATABASE TestDB_DiffCollation;
GO

-- 步驟4:使用統(tǒng)一排序規(guī)則創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE TestDB_DiffCollation
COLLATE Chinese_PRC_CI_AS;
GO

-- 步驟5:導(dǎo)入數(shù)據(jù)和對(duì)象

6.2 解決方案 2:使用 COLLATE 子句

-- 在查詢中顯式指定排序規(guī)則

-- 跨庫查詢
SELECT a.col1, b.col2
FROM DB1.dbo.TableA a
INNER JOIN DB2.dbo.TableB b
    ON a.join_col COLLATE DATABASE_DEFAULT = b.join_col COLLATE DATABASE_DEFAULT;

-- 字符串比較
DECLARE @var1 VARCHAR(50) = 'test';
DECLARE @var2 VARCHAR(50) = 'TEST';

IF @var1 COLLATE Chinese_PRC_CI_AS = @var2 COLLATE Chinese_PRC_CI_AS
    PRINT 'Equal';

-- ORDER BY 指定排序規(guī)則
SELECT name FROM users
ORDER BY name COLLATE Chinese_PRC_CI_AS;

6.3 解決方案 3:修改列的排序規(guī)則

-- 修改現(xiàn)有列的排序規(guī)則

-- 注意:修改列排序規(guī)則會(huì)重建表,大表操作需要謹(jǐn)慎

-- 示例:修改列排序規(guī)則
ALTER TABLE TestTable
ALTER COLUMN col1 VARCHAR(50) COLLATE Chinese_PRC_CI_AS;
GO

-- 查看列排序規(guī)則修改結(jié)果
SELECT name, collation_name
FROM sys.columns
WHERE object_id = OBJECT_ID('TestTable');
GO

6.4 解決方案 4:使用計(jì)算列

-- 創(chuàng)建計(jì)算列用于跨庫連接

CREATE TABLE TableA
(
    id INT PRIMARY KEY,
    code VARCHAR(20),
    -- 計(jì)算列:統(tǒng)一排序規(guī)則
    code_normalized AS code COLLATE Chinese_PRC_CI_AS PERSISTED
);
GO

-- 創(chuàng)建表
CREATE TABLE TableB
(
    id INT PRIMARY KEY,
    code VARCHAR(20) COLLATE Chinese_PRC_CS_AS
);
GO

-- 使用計(jì)算列進(jìn)行連接
SELECT a.id, b.id
FROM TableA a
INNER JOIN TableB b ON a.code_normalized = b.code COLLATE Chinese_PRC_CI_AS;
GO

七、最佳實(shí)踐建議

7.1 設(shè)計(jì)階段建議

建議說明
統(tǒng)一規(guī)劃實(shí)例安裝前規(guī)劃好排序規(guī)則,盡量統(tǒng)一
測試先行在開發(fā)環(huán)境測試不同排序規(guī)則的影響
文檔記錄記錄每個(gè)數(shù)據(jù)庫和表的排序規(guī)則配置
代碼規(guī)范在跨庫查詢中始終使用 COLLATE 子句

7.2 開發(fā)階段建議

-- 建議在存儲(chǔ)過程和視圖中使用 DATABASE_DEFAULT

CREATE VIEW vw_CrossDatabaseJoin AS
SELECT
    a.id AS id_a,
    b.id AS id_b,
    a.col1,
    b.col2
FROM DB1.dbo.TableA a
INNER JOIN DB2.dbo.TableB b
    ON a.join_key COLLATE DATABASE_DEFAULT = b.join_key COLLATE DATABASE_DEFAULT;
GO

7.3 運(yùn)維階段建議

建議說明
定期檢查定期檢查數(shù)據(jù)庫和列的排序規(guī)則配置
監(jiān)控性能監(jiān)控因排序規(guī)則導(dǎo)致的性能問題
變更管理排序規(guī)則變更需要經(jīng)過嚴(yán)格測試

7.4 監(jiān)控 SQL

-- 監(jiān)控因排序規(guī)則導(dǎo)致的查詢警告

SELECT
    st.text AS SQLText,
    SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
        ((CASE qs.statement_end_offset
            WHEN -1 THEN DATALENGTH(st.text)
            ELSE qs.statement_end_offset
        END - qs.statement_start_offset)/2) + 1) AS StatementText,
    qp.query_plan,
    qs.execution_count,
    qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE st.text LIKE '%COLLATE%'
   OR qp.query_plan.exist('//*[local-name()="PlanAffectingConvert"]') = 1
ORDER BY avg_elapsed_time DESC;
GO

八、驗(yàn)證檢查清單

檢查項(xiàng)狀態(tài)說明
實(shí)例排序規(guī)則已確認(rèn)? 確認(rèn)使用 SERVERPROPERTY('Collation') 查看
所有數(shù)據(jù)庫排序規(guī)則已記錄? 確認(rèn)使用 sys.databases 查詢
列級(jí)別排序規(guī)則已檢查? 確認(rèn)檢查關(guān)鍵表的列排序規(guī)則
跨庫查詢已測試? 確認(rèn)驗(yàn)證跨庫 JOIN 是否正常
臨時(shí)表查詢已測試? 確認(rèn)驗(yàn)證與臨時(shí)表的交互
字符串處理已測試? 確認(rèn)驗(yàn)證字符串比較和排序
性能影響已評(píng)估? 確認(rèn)檢查是否因排序規(guī)則導(dǎo)致性能問題
解決方案已確定? 確認(rèn)針對(duì)不一致問題制定解決方案

九、診斷 SQL 腳本

9.1 全面診斷腳本

-- SQL Server 字符集診斷腳本

-- 1. 實(shí)例級(jí)排序規(guī)則
PRINT '=== 實(shí)例級(jí)排序規(guī)則 ===';
SELECT
    SERVERPROPERTY('Collation') AS InstanceCollation,
    SERVERPROPERTY('Edition') AS ServerEdition,
    SERVERPROPERTY('ProductVersion') AS ProductVersion;
GO

-- 2. 所有數(shù)據(jù)庫排序規(guī)則
PRINT '=== 所有數(shù)據(jù)庫排序規(guī)則 ===';
SELECT
    database_id,
    name AS DatabaseName,
    collation_name AS Collation,
    compatibility_level AS CompatibilityLevel,
    state_desc AS State,
    CASE
        WHEN collation_name = SERVERPROPERTY('Collation') THEN '? 一致'
        ELSE '? 不一致'
    END AS MatchInstance
FROM sys.databases
ORDER BY database_id;
GO

-- 3. 不一致數(shù)據(jù)庫詳情
PRINT '=== 與實(shí)例排序規(guī)則不一致的數(shù)據(jù)庫 ===';
SELECT
    name AS DatabaseName,
    collation_name AS DatabaseCollation,
    SERVERPROPERTY('Collation') AS InstanceCollation
FROM sys.databases
WHERE collation_name <> SERVERPROPERTY('Collation')
  AND database_id > 4;  -- 排除系統(tǒng)數(shù)據(jù)庫
GO

-- 4. 列級(jí)別排序規(guī)則統(tǒng)計(jì)
PRINT '=== 列級(jí)別排序規(guī)則統(tǒng)計(jì) ===';
SELECT
    OBJECT_NAME(c.object_id) AS TableName,
    c.name AS ColumnName,
    ty.name AS DataType,
    c.collation_name AS ColumnCollation,
    DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS DatabaseCollation,
    CASE
        WHEN c.collation_name = DATABASEPROPERTYEX(DB_NAME(), 'Collation') THEN '? 一致'
        ELSE '? 不一致'
    END AS MatchDatabase
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types ty ON c.system_type_id = ty.system_type_id
WHERE t.is_ms_shipped = 0  -- 排除系統(tǒng)表
  AND c.collation_name IS NOT NULL
ORDER BY OBJECT_NAME(c.object_id), c.column_id;
GO

-- 5. 不同代碼頁的列
PRINT '=== 使用不同代碼頁的列 ===';
SELECT
    DB_NAME() AS DatabaseName,
    OBJECT_NAME(c.object_id) AS TableName,
    c.name AS ColumnName,
    c.collation_name AS Collation,
    COLLATIONPROPERTY(c.collation_name, 'CodePage') AS CodePage
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.is_ms_shipped = 0
  AND c.collation_name IS NOT NULL
GROUP BY c.collation_name, COLLATIONPROPERTY(c.collation_name, 'CodePage')
ORDER BY CodePage;
GO

9.2 生成修復(fù)建議

-- 生成修復(fù)建議腳本

DECLARE @InstanceCollation NVARCHAR(128);
SET @InstanceCollation = CAST(SERVERPROPERTY('Collation') AS NVARCHAR(128));

-- 生成修改數(shù)據(jù)庫排序規(guī)則的腳本
SELECT
    'ALTER DATABASE [' + name + '] COLLATE ' + @InstanceCollation + ';' AS FixScript,
    '注意:修改數(shù)據(jù)庫排序規(guī)則不影響現(xiàn)有列,需要單獨(dú)修改列' AS Warning
FROM sys.databases
WHERE collation_name <> @InstanceCollation
  AND database_id > 4;

-- 生成修改列排序規(guī)則的腳本
SELECT
    'ALTER TABLE [' + SCHEMA_NAME(t.schema_id) + '].[' + t.name + '] ' +
    'ALTER COLUMN [' + c.name + '] ' +
    UPPER(ty.name) +
    CASE
        WHEN ty.name IN ('varchar', 'char', 'nvarchar', 'nchar') THEN '(' + CAST(c.max_length AS VARCHAR) + ')'
        ELSE ''
    END +
    ' COLLATE ' + @InstanceCollation + ';' AS FixScript,
    '注意:修改列排序規(guī)則會(huì)重建表,大表操作需謹(jǐn)慎' AS Warning
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
WHERE t.is_ms_shipped = 0
  AND c.collation_name IS NOT NULL
  AND c.collation_name <> @InstanceCollation
ORDER BY SCHEMA_NAME(t.schema_id), t.name, c.column_id;
GO

十、常見問題

Q1:如何判斷字符集不一致是否影響了性能?

診斷方法:

-- 查看執(zhí)行計(jì)劃中的排序規(guī)則轉(zhuǎn)換警告
SELECT
    qs.execution_count,
    qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time,
    st.text AS SQLText,
    qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qp.query_plan.exist('//*[local-name()="Sort"][@Implicit="1"]') = 1
   OR st.text LIKE '%COLLATE%'
ORDER BY avg_elapsed_time DESC;

Q2:修改數(shù)據(jù)庫排序規(guī)則會(huì)影響數(shù)據(jù)嗎?

回答:

  • 修改數(shù)據(jù)庫排序規(guī)則只影響新創(chuàng)建的對(duì)象
  • 現(xiàn)有的列保持原有的排序規(guī)則
  • 需要單獨(dú)修改每列的排序規(guī)則

Q3:如何選擇合適的排序規(guī)則?

建議:

  • 國內(nèi)應(yīng)用:Chinese_PRC_CI_AS
  • 國際化應(yīng)用:Latin1_General_CI_AS
  • 安全敏感應(yīng)用:Chinese_PRC_CS_AS 或 Chinese_PRC_BIN
  • 與實(shí)例保持一致是最簡單的選擇

Q4:排序規(guī)則與 Unicode 的關(guān)系?

說明:

  • VARCHAR/CHAR:使用代碼頁,受排序規(guī)則影響
  • NVARCHAR/NCHAR:Unicode 字符,排序規(guī)則只影響排序和比較,不影響存儲(chǔ)
  • 推薦使用 NVARCHAR 存儲(chǔ)多語言數(shù)據(jù)

十一、補(bǔ)充測試驗(yàn)證結(jié)果

11.1 測試環(huán)境

項(xiàng)目內(nèi)容
測試實(shí)例mssql-1c247f8d00-0 (Kubernetes Pod)
實(shí)例排序規(guī)則Chinese_PRC_CI_AS
測試時(shí)間2026-03-16
測試執(zhí)行者Claude Code

11.2 創(chuàng)建的敏感測試數(shù)據(jù)庫

數(shù)據(jù)庫名稱排序規(guī)則與實(shí)例一致代碼頁用途
TestDB_Chinese_BINChinese_PRC_BIN?936二進(jìn)制排序測試
TestDB_DiffCollationChinese_PRC_CS_AS?936大小寫敏感測試
TestDB_Latin1_CI_ASLatin1_General_CI_AS?1252拉丁字符集測試
TestDB_SameCollationChinese_PRC_CI_AS?936與實(shí)例一致測試
TestDB_UTF8_Chinese_PRC_CI_ASChinese_PRC_CI_AS?936UTF8兼容測試

11.3 實(shí)際驗(yàn)證結(jié)果

測試 1:大小寫不敏感 (Chinese_PRC_CI_AS)

-- 測試環(huán)境:TestDB_SameCollation (Chinese_PRC_CI_AS)
CREATE TABLE TestCaseSensitivity (
    id INT,
    name VARCHAR(50)
);
INSERT INTO TestCaseSensitivity VALUES (1, 'abc'), (2, 'ABC'), (3, 'aBc');

SELECT COUNT(*) FROM TestCaseSensitivity WHERE name = 'abc';

實(shí)際結(jié)果: 返回 3 行
結(jié)論: ? 驗(yàn)證通過 - Chinese_PRC_CI_AS 大小寫不敏感

測試 2:大小寫敏感 (Chinese_PRC_CS_AS)

-- 測試環(huán)境:TestDB_DiffCollation (Chinese_PRC_CS_AS)
CREATE TABLE TestCaseSensitivity_CS (
    id INT,
    name VARCHAR(50)
);
INSERT INTO TestCaseSensitivity_CS VALUES (1, 'abc'), (2, 'ABC'), (3, 'aBc');

SELECT COUNT(*) FROM TestCaseSensitivity_CS WHERE name = 'abc';

實(shí)際結(jié)果: 返回 1 行
結(jié)論: ? 驗(yàn)證通過 - Chinese_PRC_CS_AS 大小寫敏感

測試 3:二進(jìn)制排序 (Chinese_PRC_BIN)

-- 測試環(huán)境:TestDB_Chinese_BIN (Chinese_PRC_BIN)
CREATE TABLE TestCaseBIN (id INT, name VARCHAR(50));
INSERT INTO TestCaseBIN VALUES (1, 'abc'), (2, 'ABC'), (3, '測試');

SELECT COUNT(*) FROM TestCaseBIN WHERE name = 'abc';

實(shí)際結(jié)果: 返回 1 行
結(jié)論: ? 驗(yàn)證通過 - Chinese_PRC_BIN 二進(jìn)制排序,嚴(yán)格區(qū)分大小寫

測試 4:拉丁字符集 (Latin1_General_CI_AS)

-- 測試環(huán)境:TestDB_Latin1_CI_AS
CREATE TABLE TestLatin1 (id INT, content VARCHAR(50));
INSERT INTO TestLatin1 VALUES (1, 'test'), (2, '中文測試');

SELECT * FROM TestLatin1 WHERE content = 'test';

實(shí)際結(jié)果: 成功存儲(chǔ)和查詢中文字符
結(jié)論: ? 驗(yàn)證通過 - Latin1 字符集也能處理中文(推薦使用 NVARCHAR)

測試 5:跨庫 JOIN 排序規(guī)則沖突

-- 測試:Chinese_PRC_BIN 與 Latin1_General_CI_AS 跨庫 JOIN
SELECT a.id
FROM TestDB_Latin1_CI_AS.dbo.TestLatin1 a
INNER JOIN TestDB_Chinese_BIN.dbo.TableBIN b ON a.content = b.code;

實(shí)際結(jié)果:

Msg 468, Level 16, State 9
Cannot resolve the collation conflict between "Chinese_PRC_BIN" and "Latin1_General_CI_AS"

結(jié)論: ? 驗(yàn)證通過 - 不同排序規(guī)則跨庫 JOIN 報(bào)錯(cuò)

測試 6:tempdb 排序規(guī)則

實(shí)際查詢結(jié)果:

  • TestDB_DiffCollation 排序規(guī)則: Chinese_PRC_CS_AS
  • tempdb 排序規(guī)則: Chinese_PRC_CI_AS

結(jié)論: ? 驗(yàn)證通過 - 臨時(shí)表與用戶數(shù)據(jù)庫排序規(guī)則不一致

11.4 補(bǔ)充測試結(jié)論

測試項(xiàng)預(yù)期行為實(shí)際結(jié)果狀態(tài)
大小寫不敏感查詢匹配所有大小寫組合返回 3 行? 通過
大小寫敏感查詢僅匹配精確大小寫返回 1 行? 通過
二進(jìn)制排序查詢嚴(yán)格區(qū)分大小寫返回 1 行? 通過
拉丁字符集存儲(chǔ)中文可存儲(chǔ)中文成功? 通過
跨庫 JOIN 沖突報(bào)錯(cuò) Msg 468報(bào)錯(cuò) Msg 468? 通過
tempdb 排序規(guī)則與用戶數(shù)據(jù)庫不同不同? 通過

11.5 驗(yàn)證檢查清單(更新)

檢查項(xiàng)狀態(tài)驗(yàn)證時(shí)間
實(shí)例排序規(guī)則已確認(rèn)? 已驗(yàn)證2026-03-16
不同排序規(guī)則數(shù)據(jù)庫已創(chuàng)建? 已驗(yàn)證2026-03-16
大小寫敏感/不敏感已測試? 已驗(yàn)證2026-03-16
二進(jìn)制排序已測試? 已驗(yàn)證2026-03-16
跨庫 JOIN 沖突已驗(yàn)證? 已驗(yàn)證2026-03-16
COLLATE 子句解決方案已驗(yàn)證? 已驗(yàn)證2026-03-16
臨時(shí)表排序規(guī)則已確認(rèn)? 已驗(yàn)證2026-03-16

十二、參考資源

資源說明
排序規(guī)則和 Unicode 支持Microsoft 官方文檔
COLLATE 子句Transact-SQL 語法
設(shè)置或更改列排序規(guī)則數(shù)據(jù)庫引擎操作指南

到此這篇關(guān)于SQL Server 字符集驗(yàn)證的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SQL 字符集驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SQL Server 2005 還原數(shù)據(jù)庫錯(cuò)誤解決方法

    SQL Server 2005 還原數(shù)據(jù)庫錯(cuò)誤解決方法

    解決SQL Server 2005 還原數(shù)據(jù)庫錯(cuò)誤:System.Data.SqlClient.SqlError: 在對(duì) 'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\BusinessDB.mdf' 嘗試 'RestoreContainer::ValidateTargetForCreation' 時(shí),操作系統(tǒng)返回了錯(cuò)誤 '5(拒絕訪問)'
    2009-03-03
  • SQL Server數(shù)據(jù)庫簡單的事務(wù)日志備份恢復(fù)流程

    SQL Server數(shù)據(jù)庫簡單的事務(wù)日志備份恢復(fù)流程

    在一些對(duì)數(shù)據(jù)可靠性要求很高的行業(yè),若發(fā)生意外停機(jī)或數(shù)據(jù)丟失,其損失是十分慘重的,數(shù)據(jù)庫管理員應(yīng)針對(duì)具體的業(yè)務(wù)要求指定詳細(xì)的數(shù)據(jù)庫備份與災(zāi)難恢復(fù)策略,本文給大家詳細(xì)介紹了SQL Server數(shù)據(jù)庫簡單的事務(wù)日志備份恢復(fù)流程,需要的朋友可以參考下
    2024-09-09
  • Sql Server 2000 行轉(zhuǎn)列的實(shí)現(xiàn)(橫排)

    Sql Server 2000 行轉(zhuǎn)列的實(shí)現(xiàn)(橫排)

    在一些統(tǒng)計(jì)報(bào)表中,常常會(huì)用到將行結(jié)果用列形式展現(xiàn)。我們這里用一個(gè)常見的學(xué)生各門課程的成績報(bào)表,來實(shí)際展示實(shí)現(xiàn)方法。
    2008-11-11
  • SQL Server Table中XML列的操作代碼

    SQL Server Table中XML列的操作代碼

    SQL Server Table中XML列的操作代碼,需要的朋友可以參考下。
    2011-10-10
  • sqlserver中觸發(fā)器+游標(biāo)操作實(shí)現(xiàn)

    sqlserver中觸發(fā)器+游標(biāo)操作實(shí)現(xiàn)

    sqlserver中觸發(fā)器+游標(biāo)操作實(shí)現(xiàn),需要的朋友可以參考下
    2012-11-11
  • SQL cursor用法實(shí)例

    SQL cursor用法實(shí)例

    這篇文章介紹了SQL cursor用法實(shí)例,有需要的朋友可以參考一下
    2013-09-09
  • 提升SQL Server速度 整理索引碎片

    提升SQL Server速度 整理索引碎片

    數(shù)據(jù)庫表A有十萬條記錄,查詢速度本來還可以,但導(dǎo)入一千條數(shù)據(jù)后,問題出現(xiàn)了。當(dāng)選擇的數(shù)據(jù)在原十萬條記錄之間時(shí),速度還是挺快的;但當(dāng)選擇的數(shù)據(jù)在這一千條數(shù)據(jù)之間時(shí),速度變得奇慢
    2009-07-07
  • sql server代理中作業(yè)執(zhí)行SSIS包失敗的解決辦法

    sql server代理中作業(yè)執(zhí)行SSIS包失敗的解決辦法

    這篇文章主要介紹了sql server代理中作業(yè)執(zhí)行SSIS包失敗的解決辦法,sql2005如何用dtexec運(yùn)行ssis(DTS)包?本文講的非常詳細(xì),小伙伴們一起學(xué)習(xí)吧
    2015-09-09
  • SQL Server誤區(qū)30日談 第26天 SQL Server中存在真正的“事務(wù)嵌套”

    SQL Server誤區(qū)30日談 第26天 SQL Server中存在真正的“事

    嵌套事務(wù)可不會(huì)像其語法表現(xiàn)的那樣看起來允許事務(wù)嵌套。我真不知道為什么有人會(huì)這樣寫代碼,我唯一能夠想到的就是某個(gè)哥們對(duì)SQL Server社區(qū)嗤之以鼻然后寫了這樣的代碼說:“玩玩你們”
    2013-01-01
  • SQL Server INSERT操作實(shí)戰(zhàn)與腳本生成方法

    SQL Server INSERT操作實(shí)戰(zhàn)與腳本生成方法

    在SQL Server數(shù)據(jù)庫操作中, INSERT語句是最基礎(chǔ)且使用頻率極高的命令之一,用于向表中添加新的數(shù)據(jù)記錄,本文詳細(xì)介紹了INSERT操作的應(yīng)用場景與實(shí)現(xiàn)技巧,包括數(shù)據(jù)復(fù)制、批量插入、事務(wù)控制、錯(cuò)誤處理等內(nèi)容,感興趣的朋友跟隨小編一起看看吧
    2025-10-10

最新評(píng)論

清徐县| 句容市| 乐亭县| 凤庆县| 平阳县| 桦川县| 舟曲县| 无极县| 威信县| 石棉县| 汽车| 连州市| 新野县| 舟山市| 宁化县| 天门市| 扬州市| 中西区| 项城市| 新巴尔虎左旗| 桂平市| 社会| 梁山县| 高雄市| 丰顺县| 柘荣县| 新晃| 莆田市| 渝北区| 张北县| 古丈县| 崇礼县| 娄烦县| 于田县| 社会| 图片| 祁门县| 高阳县| 曲沃县| 新晃| 菏泽市|