簡體   English   中英

Azure SQL數據倉庫是否有分割字符串的方法?

[英]Does Azure SQL Data Warehouse have a way to split strings?

做一些研究,我發現在Azure SQL數據倉庫中拆分字符串沒有很好的選擇。 它沒有新的STRING_SPLIT()函數或OPENJSON()函數。 它也不允許用戶定義函數中的SELECT語句嘗試創建自己的,就像社區所做的許多自定義拆分器功能一樣。

因此,我想我會提出這樣的問題:SQL數據倉庫是否有分割字符串的方法以及最佳選擇?

用例

您在SQL表中有一個字段,其值為“My_Value_Is_Good”。 目標是在SELECT語句中使用分隔符下划線將每個段拆分為單獨的字段,或者最多寫入新表。

我用過的解決方案

對我來說主要的是在數據進入數據倉庫之前轉換數據。 我使用Python來解析數據。 但是,較大的數據集確實會降低速度,並將其更多地分離到系統中的特定記錄中。

20197月更新 - 現在,Azure SQL數據倉庫中的STRING_SPLIT可用於此處 所以在我下面的例子中,代碼更像是這樣的:

DECLARE @delimiter CHAR(1) = '-';

CREATE TABLE dbo.guids_split
WITH
(
    DISTRIBUTION = HASH(xguid),
    HEAP
)
AS
SELECT *
FROM dbo.guids g
    CROSS APPLY STRING_SPLIT ( xguid, @delimiter );

與普通SQL Server或Azure SQL數據庫相比,Azure SQL數據倉庫具有減少的T-SQL表面積。 它沒有任何花哨的技巧,如STRING_SPLIT ,表值函數,CLR,XML; 甚至不允許使用游標。 事實上,對於關於這個主題的一篇文章(pre-SQL 2016)中的所有技術' 以正確的方式拆分字符串 - 或者下一個最好的方式 ',你不能使用它們中的任何一個,除了數字表。

因此,我們需要更多程序性的東西,避免任何類型的循環。 我使用上面的文章作為靈感,使用了測試數據腳本的改編版本和這種方法

-- Create one million guids
IF OBJECT_ID('dbo.numbers') IS NOT NULL DROP TABLE dbo.numbers
IF OBJECT_ID('dbo.guids_split') IS NOT NULL DROP TABLE dbo.guids_split
IF OBJECT_ID('dbo.guids') IS NOT NULL DROP TABLE dbo.guids
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
GO


CREATE TABLE dbo.Numbers (
    Number  INT NOT NULL
)
WITH
(
    DISTRIBUTION = ROUND_ROBIN,     --!!TODO try distibuting?
    CLUSTERED INDEX ( Number )
)
GO


DECLARE @UpperLimit INT = 1000000;

;WITH n AS
(
    SELECT
        x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
    FROM       sys.all_objects AS s1
    CROSS JOIN sys.all_objects AS s2
    CROSS JOIN sys.all_objects AS s3
)
SELECT x
INTO #tmp
FROM n
WHERE x BETWEEN 1 AND @UpperLimit
GO

INSERT INTO dbo.Numbers ( Number )
SELECT x
FROM #tmp
GO


CREATE TABLE dbo.guids (
    rn  INT IDENTITY,
    xguid   CHAR(36) NOT NULL
)
WITH
(
    DISTRIBUTION = HASH(xguid),
    CLUSTERED COLUMNSTORE INDEX
)
GO

INSERT INTO dbo.guids ( xguid )
SELECT NEWID() xguid
FROM dbo.Numbers
GO -- 10    -- scale up 10 to 100, 1,000 etc

ALTER INDEX ALL ON dbo.guids REBUILD 
GO


-- Create the stats
CREATE STATISTICS _st_numbers_number ON dbo.numbers (number);
CREATE STATISTICS _st_guids_rn ON dbo.guids (rn);
CREATE STATISTICS _st_guids_xguid ON dbo.guids (xguid);
GO
-- multi-col stat?
:exit


-- NB The length of the guid; so we don't have to use VARCHAR(MAX)
DECLARE @delimiter VARCHAR(1) = '-';

CREATE TABLE dbo.guids_split
WITH
(
    DISTRIBUTION = HASH(xguid),
    HEAP
)
AS
SELECT
    s.rn,
    n.Number n,
    originalid AS xguid,
    LTRIM( RTRIM( SUBSTRING( s.xguid, n.Number + 1, CHARINDEX( @delimiter, s.xguid, n.Number + 1 ) - n.Number - 1 ) ) ) AS split_value
FROM (
    SELECT
        rn,
        xguid AS originalid,
        CAST( CAST( @delimiter AS VARCHAR(38) ) + CAST( xguid AS VARCHAR(38) ) + CAST( @delimiter AS VARCHAR(38) ) AS VARCHAR(38) ) AS xguid
        FROM dbo.guids
        ) s
    CROSS JOIN dbo.Numbers n
WHERE n.Number < LEN( s.xguid )
  AND SUBSTRING( s.xguid, n.Number, 1 ) = @delimiter;
GO


/*
SELECT TOP 10 * FROM dbo.guids ORDER BY rn;

SELECT *
FROM dbo.guids_split
WHERE rn In ( SELECT TOP 10 rn FROM dbo.guids ORDER BY rn )
ORDER BY 1, 2;
GO

*/

該腳本現在在ADW上進行了測試,並且令人滿意地工作了超過1億條記錄。 僅在DWU 400下運行不到4分鍾(至少一次我添加了統計數據並刪除了varchar(max) :)。 然而,guids是一個略微人為的例子,因為數據大小一致,並且總是只有5個部分要分開。

從Azure SQL數據倉庫中獲得良好的性能實際上與通過良好的哈希分發密鑰最小化數據移動有關。 因此,請發布一些實際的樣本數據。

另一種選擇是Azure Data Lake Analytics。 ADLA支持聯合查詢“查詢它所在的數據”,因此您可以使用U-SQL查詢原始表,使用本機.net方法對其進行拆分並輸出可以使用Polybase輕松導入的方法。 如果您需要有關此方法的更多幫助,請告訴我,我會舉一個例子。

SQLCat團隊已經發布了關於SQL數據倉庫反模式的這篇文章,這種類型的字符串處理可能被認為是一個例子。 請閱讀這篇文章:

https://blogs.msdn.microsoft.com/sqlcat/2017/09/05/azure-sql-data-warehouse-workload-patterns-and-anti-patterns/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM