如何有效地排序包含数字和字母的nvarchar?

时间:2017-04-25 09:33:00

标签: sql-server tsql

我遇到了一些有效排序表的麻烦(该表包含大量行,因此任何优化都会产生很大的不同)。

我目前拥有的正确结果(11)是下面的代码。

BEGIN TRANSACTION

    CREATE TABLE #tPallets
    (
      PalletNumber bigint,
      Placement nvarchar(4)
    )

    INSERT INTO #tPallets  VALUES(100000, 'B')   
    INSERT INTO #tPallets  VALUES(100001, 'M1')  
    INSERT INTO #tPallets  VALUES(100002, 'M2')  
    INSERT INTO #tPallets  VALUES(100003, 'M3')  
    INSERT INTO #tPallets  VALUES(100004, 'M4')  
    INSERT INTO #tPallets  VALUES(100005, 'M5')  
    INSERT INTO #tPallets  VALUES(100006, 'M6')  
    INSERT INTO #tPallets  VALUES(100007, 'M7')  
    INSERT INTO #tPallets  VALUES(100008, 'M8')  
    INSERT INTO #tPallets  VALUES(100009, 'M9')  
    INSERT INTO #tPallets  VALUES(100010, 'M10')  
    INSERT INTO #tPallets  VALUES(100011, 'M11')  

    SELECT 
        TOP 1 CASE 
            WHEN Placement LIKE 'M%' THEN CONVERT(int, SUBSTRING(Placement,2, len(Placement)-1)) 
            ELSE 0 
        END AS PALLET_PLACEMENT 
    FROM 
        #tPallets 
    ORDER BY 
        1 DESC

ROLLBACK TRANSACTION

所以我正在寻找一种方法来使选择更快,如果在这种特定情况下可能的话。

我不认为这是答案的重复。因为线程中没有答案会使得执行时间更快而不在C#中进行排序(而不是在TSql中进行排序)。而且我很难相信在TSql本身没有更快的方法。

3 个答案:

答案 0 :(得分:0)

您提供的详细信息,请尝试这种方式。

CREATE TABLE #tPallets
    (
      PalletNumber bigint,
      Placement nvarchar(4),
      OrderBy as CASE 
            WHEN Placement LIKE 'M%' THEN CONVERT(int, SUBSTRING(Placement,2, len(Placement)-1)) 
            ELSE 0 END
    )

    INSERT INTO #tPallets  VALUES(100000, 'B')   
    INSERT INTO #tPallets  VALUES(100001, 'M1')  
    INSERT INTO #tPallets  VALUES(100002, 'M2')  
    INSERT INTO #tPallets  VALUES(100003, 'M3')  
    INSERT INTO #tPallets  VALUES(100004, 'M4')  
    INSERT INTO #tPallets  VALUES(100005, 'M5')  
    INSERT INTO #tPallets  VALUES(100006, 'M6')  
    INSERT INTO #tPallets  VALUES(100007, 'M7')  
    INSERT INTO #tPallets  VALUES(100008, 'M8')  
    INSERT INTO #tPallets  VALUES(100009, 'M9')  
    INSERT INTO #tPallets  VALUES(100010, 'M10')  
    INSERT INTO #tPallets  VALUES(100011, 'M11')  

    select * from #tPallets
    order by OrderBy

或者尝试这个但不确定。

select * from #tPallets
order by BINARY_CHECKSUM(Placement) desc

答案 1 :(得分:0)

计算列https://docs.microsoft.com/en-us/sql/relational-databases/indexes/indexes-on-computed-columns

的索引

或者,在您的情况下可能更好地结合使用过滤索引

https://docs.microsoft.com/en-us/sql/relational-databases/indexes/create-filtered-indexes

摆脱那些讨厌的0。 (顺便说一下placement不是like %M时,您对订单的期望是什么?)

答案 2 :(得分:0)

使用计算列 加快速度的方法是让列持久化,而不是在列上创建索引。请记住,这当然会对 DML(插入/更新/删除)造成性能损失

DROP TABLE IF EXISTS #tPallets
CREATE TABLE #tPallets
(
    PalletNumber bigint,
    Placement nvarchar(4),
    PALLET_PLACEMENT AS (CASE 
        WHEN Placement LIKE 'M%' THEN CONVERT(int, SUBSTRING(Placement,2, len(Placement)-1)) 
        ELSE 0 
    END) PERSISTED /*Will save the calculation in the table*/
)

INSERT INTO #tPallets
VALUES(100000, 'B')   
,(100001, 'M1')  
,(100002, 'M2')  
,(100003, 'M3')  
,(100004, 'M4')  
,(100005, 'M5')  
,(100006, 'M6')  
,(100007, 'M7')  
,(100008, 'M8')  
,(100009, 'M9')  
,(100010, 'M10')  
,(100011, 'M11')  

/*Can create this to speed up the query*/
CREATE INDEX ix_test on #tPallets (PALLET_PLACEMENT) INCLUDE (PalletNumber,Placement)

SELECT *
FROM  #tPallets 
ORDER BY PALLET_PLACEMENT DESC