Tôi đặt đây là một câu trả lời mới, vì nó không thực sự là một câu trả lời mà là sự so sánh giữa các phương pháp tiếp cận khác nhau:
Kết luận:
- tất cả các phương pháp tiếp cận đều có quy mô khá tuyến tính, ngoại trừ XML
- XML nhanh nhất với số lượng hàng nhỏ nhưng trở nên tồi tệ hơn với số lượng hàng cao
Tạo một kịch bản thử nghiệm
CREATE TABLE #tbl (ID INT IDENTITY,sortColumn VARCHAR(100));
INSERT INTO #tbl VALUES
('A-1')
,('A-10')
,('A-2')
,('A-3')
,('A-4')
,('A-5')
,('A-6')
,('A-7')
,('A-8')
,('A-9')
,('A-3a')
,('A-3b')
,('A-3c')
,('B-1')
,('B-10')
,('B-11')
,('B-12')
,('B-12a')
,('B-12b')
,('B-13')
,('B-2')
,('B-3')
,('B-4')
,('B-5')
,('B-6')
,('B-7')
,('B-8')
,('A-8a')
,('B-8')
,('B-9'); --30 rows
GO 1000 -- x 1.000 = 30.000 rows
Cách tiếp cận của Matt (được làm sạch đến mức cần thiết)
- 46 giây trên 3 mio hàng
- 4,5 giây trên 300.000 hàng
- 1,3 giây trên 30.000 hàng
- 0,7 giây trên 3.000 hàng
Mã
SELECT ID,sortColumn
FROM
#tbl
ORDER BY
LEFT(sortColumn,CHARINDEX('-',sortColumn) -1)
,CAST((CASE
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)
ELSE NULL
END) AS INT)
,RIGHT(sortColumn,
LEN(sortColumn) -
LEN(LEFT(sortColumn,CHARINDEX('-',sortColumn) -1))
- LEN(CASE
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)
WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)
ELSE NULL
END)
- 1 --the '-'
),ID;
Tính toán từng bước trong CROSS APPLY
sắp xếp, sắp xếp trên các cột được tính toán
- 44 giây trên 3 mio hàng
- 4,4 giây trên 300.000 hàng
- 0,9 giây trên 30.000 hàng
- 0,3 giây trên 3.000 hàng
Mã
SELECT ID,sortColumn
FROM #tbl
CROSS APPLY(SELECT CHARINDEX('-',sortColumn) AS posMinus) AS pos
CROSS APPLY(SELECT SUBSTRING(sortColumn,1,posMinus-1) AS part1
,SUBSTRING(sortColumn,posMinus+1,1000) AS part2
) AS parts
CROSS APPLY(SELECT ISNUMERIC(part2) AS p2isnum) AS checknum
CROSS APPLY(SELECT CASE WHEN p2isnum=1 THEN '' ELSE RIGHT(part2,1) END AS part3
,CASE WHEN p2isnum=1 THEN part2 ELSE SUBSTRING(part2,1,LEN(part2)-1) END AS part2New
) AS partsNew
ORDER BY part1,part2new,part3,ID;
Tính toán từng bước trong CROSS APPLY
sắp xếp, sắp xếp theo chuỗi có đệm được nối
- 42 giây trên 3 hàng mio
- 4,2 giây trên 300.000 hàng
- 0,7 giây trên 30.000 hàng
- 0,4 giây trên 3.000 hàng
Mã
SELECT ID,sortColumn
FROM #tbl
CROSS APPLY(SELECT CHARINDEX('-',sortColumn) AS posMinus) AS pos
CROSS APPLY(SELECT SUBSTRING(sortColumn,1,posMinus-1) AS part1
,SUBSTRING(sortColumn,posMinus+1,1000) AS part2
) AS parts
ORDER BY RIGHT('.....' + part1,5) + RIGHT('.....' + part2,5 - ISNUMERIC(RIGHT(part2,1)))
,ID;
Tách bằng XML, sắp xếp theo chuỗi có đệm được nối
- 67 giây trên 3 mio hàng
- 6,2 giây trên 300.000 hàng
- 0,7 giây trên 30.000 hàng
- 0,3 giây trên 3.000 hàng
Mã
SELECT ID,sortColumn
FROM
(
SELECT CAST('<r>' + REPLACE(sortColumn,'-','</r><r>') + '</r>' AS XML) AS SortColumnSplitted
,*
FROM #tbl
) AS tbl
ORDER BY RIGHT('.....' + SortColumnSplitted.value('r[1]','varchar(max)'),5) + RIGHT('.....' + SortColumnSplitted.value('r[2]','varchar(max)'),5 - ISNUMERIC(RIGHT(SortColumnSplitted.value('r[2]','varchar(max)'),1)))
,ID;