MR
は文字列であり、たとえば、数値を気にしないため、より24
下位にソートされます。>のため、これは以前3
の並べ替えのようなものです。Smith
Azlea
z
m
数値だけを数値として扱いたい場合は、MR
プレフィックスを保存しないでください。列名に基づいて、これは完全に冗長に見えます。数値部分だけを として保存し、実行時INT
に を追加するビューを作成してみませんか? 'MR'
これは、アプリに実際に影響を与えることなく簡単に実行できます (ストアド プロシージャを介して挿入/更新操作を制御できない場合は、代わりにトリガーを追加します)。
CREATE VIEW dbo.users_appended
AS
SELECT MR = 'MR' + CONVERT(VARCHAR(25), MR),
MRSort = MR --, ... other columns ...
FROM dbo.users;
GO
SELECT MR, other columns
FROM dbo.users_appended
ORDER BY MRSort;
スキーマを変更できない場合は、次のように言えます。
ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
MR
しかし、そこに保管するべきではなかったと思います。これを変更できない場合は、文字列の数値部分を引き出すビューまたは計算列を検討してください。一般的に一方向のみに順序付けする場合は、計算列にインデックスを付けることもできます。
ALTER TABLE dbo.users ADD MRNumber
AS (CONVERT(BIGINT, SUBSTRING(MR, 3, 25))) PERSISTED;
CREATE INDEX ix_mrnumber ON dbo.users(MRNumber);
計算された列とインデックスを維持するために必要な作業が、これがクエリに与える違いによって正当化されるかどうかをテストする必要があります。
ビューは似ていますが、インデックスから効率は得られません。
CREATE VIEW dbo.users_extended
AS
SELECT MR, ..., MRNumber = CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
GO
SELECT MR, ...
FROM dbo.users_extended
ORDER BY MRNumber;
代わりに使用LEN
する場合は注意してください。コードはより単純ですが、必ずしもより効率的であるとは限りません。私のシステムでは、値の分布が広い 2 つのテーブルを作成しました。
SELECT 'MR'+RTRIM(ABS(object_id)) AS MR
INTO dbo.flab
FROM sys.all_objects -- 2096 rows
SELECT 'MR'+RTRIM(ABS(s1.object_id)) AS MR
INTO dbo.mort
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2; -- 4397409 rows
ここで、次のような単純なクエリをテストします。
SELECT * FROM dbo.flab ORDER BY LEN(MR), MR;
SELECT * FROM dbo.flab ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
SELECT * FROM dbo.mort ORDER BY LEN(MR), MR;
SELECT * FROM dbo.mort ORDER BY CONVERT(BIGINT, SUBSTRING(MR, 3, 25));
ヒープの結果 (推定コストに関して SQL Server が吐き出すナンセンスにもかかわらず、期間と CPU に細心の注意を払ってください):

そして、上のクラスター化インデックスでMR
:

BIGINT
また、部分文字列が 12 文字を超える潜在的な危険を回避するために、すべての計算を に変更しました(それでも、高価な - はい、高価な - を回避しますLEN()
)。推定コストは 50/50 であり、INT
代わりに を使用した場合、期間の差はほぼ同じであることに注意してくださいBIGINT
(使用しても安全であるとINT
仮定します。値)。