sql >> データベース >  >> RDS >> Sqlserver

SQLServerの最大列制限を回避する1024および8kbのレコードサイズ

    これは単に不可能です。 内部を参照してください。ストレージエンジン:レコードの構造

    あなたのテーブルがこのようなものだと仮定します。

    CREATE TABLE T1(
        col_1 varchar(8000) NULL,
        col_2 varchar(8000) NULL,
        /*....*/
        col_999 varchar(8000) NULL,
        col_1000 varchar(8000) NULL
    ) 
    

    次に、すべての NULLを含む行も 値は次のストレージを使用します。

    • 1バイトのステータスビットA
    • 1バイトのステータスビットB
    • 2バイトの列カウントオフセット
    • 125バイトNULL_BITMAP (1ビット 1列あたり1,000列)

    つまり、これは129バイトがすでに使用されていることが保証されています(7,931を残しています)。

    いずれかの列の値がNULLでもない場合 または空の文字列の場合は、スペースも必要です

    • 2バイトの可変長列数(7,929を残す)。
    • 列オフセット配列の場合は2〜2000バイト。
    • データ自体。

    列オフセット配列は、可変長列ごとに2バイトを消費します例外 その列とそれ以降のすべての列の長さもゼロの場合。したがって、 col_1000を更新します col_1 を更新するときに、2000バイト全体が強制的に使用されます。 2バイトを使用するだけです。

    したがって、各列に5バイトのデータを入力し、列オフセット配列の各2バイトを考慮すると、残りの7,929バイト以内の7,000バイトになります。

    ただし、保存しているデータは102バイトです(51 nvarchar 文字)なので、行に残っている実際のデータへの24バイトポインタを使用して行外に格納できます。

    FLOOR(7929/(24 + 2)) = 304
    

    したがって、最良のケースは、この長さのデータの304列を格納できることです。つまり、 col_1から更新する場合です。 、 col_2 ... col_1000の場合 データが含まれている場合、計算は

    FLOOR(5929/24) = 247
    

    NTEXTの場合 計算は、16バイトのポインターを使用できる ことを除いて同様です。 これにより、データをいくつかの追加の列に圧縮できます

    FLOOR(7929/(16 + 2)) = 440
    

    SELECT については、これらすべての行外ポインタに従う必要があります テーブルに対しては、パフォーマンスに非常に悪影響を与える可能性があります。

    これをテストするためのスクリプト

    DROP TABLE T1
    
    /* Create table with 1000 columns*/
    DECLARE @CreateTableScript nvarchar(max) = 'CREATE TABLE T1('
    
    SELECT @CreateTableScript += 'col_' + LTRIM(number) + ' VARCHAR(8000),'
    FROM master..spt_values
    WHERE type='P' AND number BETWEEN 1 AND 1000
    ORDER BY number
    
    SELECT @CreateTableScript += ')'
    
    EXEC(@CreateTableScript)
    
    /* Insert single row with all NULL*/
    INSERT INTO T1 DEFAULT VALUES
    
    
    /*Updating first 304 cols succeed. Change to 305 and it fails*/
    DECLARE @UpdateTableScript nvarchar(max) = 'UPDATE T1 SET  '
    
    SELECT @UpdateTableScript += 'col_' + LTRIM(number) + ' = REPLICATE(1,1000),'
    FROM master..spt_values
    WHERE type='P' AND number BETWEEN 1 AND 304
    ORDER BY number
    
    SET @UpdateTableScript = LEFT(@UpdateTableScript,LEN(@UpdateTableScript)-1)
    EXEC(@UpdateTableScript)
    


    1. mysqlクエリを15分間隔でグループ化する

    2. MySQL-WHERE句でCOUNT(*)を使用

    3. SQL Serverの置き換え、特定の文字の後のすべてを削除

    4. Oracle PL / SQLで単純なXMLスニペットを解析し、それをグローバル一時表にロードするにはどうすればよいですか。