ก่อนอื่นขอโทษสำหรับคำตอบที่ยาวมาก ๆ เพราะฉันรู้สึกว่ายังมีความสับสนมากมายเมื่อผู้คนพูดถึงคำศัพท์เช่นการเรียงลำดับเรียงลำดับหน้ารหัส ฯลฯ
จากBOL :
collations ใน SQL Server ให้กฎการเรียงลำดับกรณีและคุณสมบัติความไวสำเนียงสำหรับข้อมูลของคุณ การจัดเรียงที่ใช้กับชนิดข้อมูลอักขระเช่น char และ varchar กำหนดรหัสหน้าและอักขระที่เกี่ยวข้องที่สามารถแสดงสำหรับชนิดข้อมูลนั้น ไม่ว่าคุณกำลังติดตั้งอินสแตนซ์ใหม่ของ SQL Server การกู้คืนการสำรองข้อมูลฐานข้อมูลหรือการเชื่อมต่อเซิร์ฟเวอร์กับฐานข้อมูลลูกค้าเป็นสิ่งสำคัญที่คุณต้องเข้าใจข้อกำหนดโลแคลลำดับการเรียงลำดับและความอ่อนไหวของข้อมูลที่คุณจะใช้ .
ซึ่งหมายความว่าการเรียงหน้ามีความสำคัญอย่างยิ่งเนื่องจากระบุกฎว่าสตริงอักขระของข้อมูลจะถูกจัดเรียงและเปรียบเทียบอย่างไร
หมายเหตุ: ข้อมูลเพิ่มเติมเกี่ยวกับCOLLATIONPROPERTY
ตอนนี้ให้เข้าใจความแตกต่างก่อน
ทำงานด้านล่าง T-SQL:
SELECT *
FROM::fn_helpcollations()
WHERE NAME IN (
'SQL_Latin1_General_CP1_CI_AS'
,'Latin1_General_CI_AS'
)
GO
SELECT 'SQL_Latin1_General_CP1_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'Version') AS 'Version'
UNION ALL
SELECT 'Latin1_General_CI_AS' AS 'Collation'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'CodePage') AS 'CodePage'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'LCID') AS 'LCID'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'ComparisonStyle') AS 'ComparisonStyle'
,COLLATIONPROPERTY('Latin1_General_CI_AS', 'Version') AS 'Version'
GO
ผลลัพธ์จะเป็น:
เมื่อดูผลลัพธ์ข้างต้นความแตกต่างเพียงอย่างเดียวคือเรียงลำดับระหว่างการเรียง 2 ครั้ง แต่นั่นไม่เป็นความจริงซึ่งคุณสามารถดูสาเหตุได้ดังนี้
ทดสอบ 1:
--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('Kin_Tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('Kin_Tester1')
--Now try to join both tables
SELECT *
FROM Table_Latin1_General_CI_AS LG
INNER JOIN Table_SQL_Latin1_General_CP1_CI_AS SLG ON LG.Comments = SLG.Comments
GO
ผลการทดสอบ 1:
Msg 468, Level 16, State 9, Line 35
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation.
จากผลลัพธ์ข้างต้นเราจะเห็นได้ว่าเราไม่สามารถเปรียบเทียบค่าโดยตรงกับคอลัมน์ที่มีการเปรียบเทียบที่แตกต่างกันคุณต้องใช้ COLLATE
เพื่อเปรียบเทียบค่าคอลัมน์
ทดสอบ 2:
ความแตกต่างที่สำคัญคือประสิทธิภาพการทำงานเป็น Erland Sommarskog ชี้ให้เห็นในการสนทนานี้ใน MSDN
--Clean up previous query
IF OBJECT_ID('Table_Latin1_General_CI_AS') IS NOT NULL
DROP TABLE Table_Latin1_General_CI_AS;
IF OBJECT_ID('Table_SQL_Latin1_General_CP1_CI_AS') IS NOT NULL
DROP TABLE Table_SQL_Latin1_General_CP1_CI_AS;
-- Create a table using collation Latin1_General_CI_AS
CREATE TABLE Table_Latin1_General_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE Latin1_General_CI_AS
)
-- add some data to it
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_Latin1_General_CI_AS (Comments)
VALUES ('kin_tester1')
-- Create second table using collation SQL_Latin1_General_CP1_CI_AS
CREATE TABLE Table_SQL_Latin1_General_CP1_CI_AS (
ID INT IDENTITY(1, 1)
,Comments VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS
)
-- add some data to it
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_test1')
INSERT INTO Table_SQL_Latin1_General_CP1_CI_AS (Comments)
VALUES ('kin_tester1')
--- สร้างดัชนีในทั้งสองตาราง
CREATE INDEX IX_LG_Comments ON Table_Latin1_General_CI_AS(Comments)
go
CREATE INDEX IX_SLG_Comments ON Table_SQL_Latin1_General_CP1_CI_AS(Comments)
--- เรียกใช้แบบสอบถาม
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = 'kin_test1'
GO
--- สิ่งนี้จะมีการแปลงโดยนัย
--- เรียกใช้แบบสอบถาม
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = 'kin_test1'
GO
--- สิ่งนี้จะไม่มีการแปลงโดยนัย
สาเหตุของการแปลงโดยนัยก็เพราะฉันมีฐานข้อมูลและการเปรียบเทียบเซิร์ฟเวอร์ของฉันทั้งสองเป็นSQL_Latin1_General_CP1_CI_AS
และตารางTable_Latin1_General_CI_ASมีคอลัมน์ความคิดเห็นที่กำหนดเช่นเดียวVARCHAR(50)
กับCOLLATE Latin1_General_CI_ASดังนั้นในระหว่างการค้นหา SQL Server จะต้องทำการแปลง IMPLICIT
ทดสอบ 3:
ด้วยการตั้งค่าเดียวกันตอนนี้เราจะเปรียบเทียบคอลัมน์ varchar กับค่า nvarchar เพื่อดูการเปลี่ยนแปลงในแผนการดำเนินการ
- เรียกใช้แบบสอบถาม
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_Latin1_General_CI_AS WHERE Comments = (SELECT N'kin_test1' COLLATE Latin1_General_CI_AS)
GO
- เรียกใช้แบบสอบถาม
DBCC FREEPROCCACHE
GO
SELECT Comments FROM Table_SQL_Latin1_General_CP1_CI_AS WHERE Comments = N'kin_test1'
GO
โปรดทราบว่าแบบสอบถามแรกสามารถทำดัชนีแสวงหา แต่ต้องทำการแปลงโดยนัยในขณะที่อันดับที่สองทำการสแกนดัชนีซึ่งพิสูจน์ว่าไม่มีประสิทธิภาพในแง่ของประสิทธิภาพเมื่อมันจะสแกนตารางขนาดใหญ่
สรุป:
- จากการทดสอบทั้งหมดข้างต้นแสดงให้เห็นว่าการเปรียบเทียบที่ถูกต้องเป็นสิ่งสำคัญมากสำหรับอินสแตนซ์เซิร์ฟเวอร์ฐานข้อมูลของคุณ
SQL_Latin1_General_CP1_CI_AS
คือการเปรียบเทียบ SQL กับกฎที่อนุญาตให้คุณเรียงลำดับข้อมูลสำหรับ unicode และ non-unicode นั้นแตกต่างกัน
- การเปรียบเทียบ SQL จะไม่สามารถใช้ดัชนีเมื่อเปรียบเทียบข้อมูล unicode และ non-unicode ดังที่เห็นในการทดสอบข้างต้นว่าเมื่อเปรียบเทียบข้อมูล nvarchar กับข้อมูล varchar จะทำการสแกนดัชนีและไม่ค้นหา
Latin1_General_CI_AS
คือการเปรียบเทียบ Windows ที่มีกฎที่อนุญาตให้คุณเรียงลำดับข้อมูลสำหรับ Unicode และ non-Unicode เหมือนกัน
- การเปรียบเทียบ Windows ยังคงสามารถใช้ดัชนี (ดัชนีค้นหาในตัวอย่างข้างต้น) เมื่อเปรียบเทียบข้อมูล unicode และ non-unicode แต่คุณเห็นว่ามีประสิทธิภาพเล็กน้อย
- ขอแนะนำให้อ่าน Erland Sommarskog คำตอบ + รายการเชื่อมต่อที่เขาชี้ไป
สิ่งนี้จะทำให้ฉันไม่มีปัญหากับ #temp tables แต่มีข้อผิดพลาดหรือไม่?
ดูคำตอบของฉันด้านบน
ฉันจะสูญเสียฟังก์ชันการทำงานหรือคุณลักษณะใด ๆ โดยไม่ใช้การจัดเรียง "ปัจจุบัน" ของ SQL 2008 หรือไม่
ทุกอย่างขึ้นอยู่กับฟังก์ชันการทำงาน / คุณสมบัติที่คุณอ้างอิง การเรียงคือการจัดเก็บและเรียงลำดับของข้อมูล
สิ่งที่เกี่ยวกับเมื่อเราย้าย (เช่นใน 2 ปี) จาก 2008 เป็น SQL 2012 ฉันจะมีปัญหาหรือไม่ ฉันจะต้องถูกบังคับให้ไปที่ Latin1_General_CI_AS หรือไม่?
ไม่สามารถรับรองได้! เนื่องจากสิ่งต่าง ๆ อาจเปลี่ยนแปลงไปและมันก็ดีเสมอที่จะสอดคล้องกับคำแนะนำของ Microsoft + คุณต้องเข้าใจข้อมูลและข้อผิดพลาดที่ฉันได้กล่าวถึงข้างต้น โปรดอ้างถึงสิ่งนี้และรายการเชื่อมต่อนี้ด้วย
ฉันอ่านว่าสคริปต์ของ DBA บางส่วนทำตามแถวของฐานข้อมูลที่สมบูรณ์แล้วเรียกใช้สคริปต์แทรกลงในฐานข้อมูลด้วยการจัดเรียงใหม่ - ฉันกลัวมากและระวังสิ่งนี้ - คุณจะแนะนำให้ทำสิ่งนี้หรือไม่
เมื่อคุณต้องการเปลี่ยนการจัดเรียงสคริปต์ดังกล่าวจะมีประโยชน์ ฉันพบว่าตัวเองกำลังเปลี่ยนการจัดเรียงฐานข้อมูลเพื่อจับคู่การจัดเรียงเซิร์ฟเวอร์หลายครั้งและฉันมีสคริปต์บางตัวที่ค่อนข้างเรียบร้อย แจ้งให้เราทราบหากคุณต้องการมัน
การอ้างอิง: