1

セッションごとに 100 列 X 500,000 行で構成されるテーブルに自動車のパフォーマンス メトリックを記録するアプリケーションを構築しています。一部の列は非常に反復的です (華氏単位の冷媒温度)。他の列は連続的に変化します (点火進角、マニホールド圧力、空燃比)。

プロジェクトはオープンソースのオーディエンスを対象としているため、列ストアとページ圧縮は問題外です。MS SQL Express Edition または大規模なテーブル サイズに対応できる別の無料のデータベース プラットフォームをサポートする必要があります。

私の最初の解決策は、いくつかの列でnullを許可することです。これにより、繰り返し値を挿入しないことでストレージのフットプリントが劇的に削減され、これによりログ解像度をより高いフレームレートに上げることができます.

ただし、特定の列が 99% null になるため、個別の行を選択するときに障害が発生します。したがって、そのフィールドに値を含む最後の行を選択するビュー (または計算列?) を作成する必要があります。私のアプローチは、スパース列ごとにサブクエリを使用することです。これはひどく非エレガントに思えます。検討すべきより効率的なアプローチはありますか?

SELECT ISNULL(
           val1,
           (
               SELECT TOP 1 val1
               FROM   [values] subv
               WHERE  subv.id <= v.id
                      AND subv.val1 IS NOT NULL
               ORDER BY
                      subv.id DESC
           )
       ) AS val1,
       ISNULL(
           val2,
           (
               SELECT TOP 1 val2
               FROM   [values] subv
               WHERE  subv.id <= v.id
                      AND subv.val2 IS NOT NULL
               ORDER BY
                      subv.id DESC
           )
       ) AS val2,
       ISNULL(
           val3,
           (
               SELECT TOP 1 val3
               FROM   [values] subv
               WHERE  subv.id <= v.id
                      AND subv.val3 IS NOT NULL
               ORDER BY
                      subv.id DESC
           )
       ) AS val3
FROM   [values] v
4

2 に答える 2

1

代わりに、3 つの列のみを含む新しいテーブルを作成することをお勧めしますMetricType, Metricvalue, MeasurementTime。特定のメトリックの値が変更された場合にのみ、新しい測定値を挿入します。

于 2013-01-17T08:57:24.693 に答える
0

私は部分的な解決策を思いつきました。

私の最初のアイデアは、呼び出し間でスカラー関数内の値を保持する方法を見つけることでした。パラメータはコピーイン/コピーアウトであるため、これは不可能であることが判明しました。テーブル値パラメーターは例外ですが、これらは読み取り専用であるため、これは役に立ちません。

代わりに、SQL-CLR を使用することにしました。C# で .NET クラスを作成して呼び出し間で値を保持し、これを SQL スカラー関数にマップしました。コードは署名されていないため、これを実行するには:

  1. データベースは信頼済みとしてマークする必要があります
  2. 静的フィールドを許可するには、CLR アセンブリを UNSAFE とマークする必要があります
  3. また、注目に値するのは、これはマルチスレッド データベース アプリケーションではなく、そのように動作することがテストされておらず、期待されていないことです。
  4. また、注目に値するのは、このソリューションの致命的な欠陥は、順序付けられた順次選択に対してのみ機能することです。

これが deploy.sql コードです (私のアセンブリは SqlClr という名前です):

sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

USE Test

ALTER DATABASE Test SET TRUSTWORTHY ON
GO

IF OBJECT_ID ('cached_value') is not null
BEGIN

    DROP FUNCTION cached_value
END
GO

IF EXISTS (SELECT * FROM sys.assemblies WHERE name = 'SqlClr') 
BEGIN
    DROP ASSEMBLY SqlClr
END
GO

CREATE ASSEMBLY SqlClr 
FROM 'C:\SqlClr\bin\Debug\SqlClr.dll'
WITH PERMISSION_SET = UNSAFE 
GO 

CREATE FUNCTION cached_value(@rowid bigint, @col int, @current_value bigint) 
RETURNS bigint
AS EXTERNAL NAME SqlClr.[SqlClr.StoredProcedures].[cached_value]

C#.NET コードは次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Server;
using System.Diagnostics;
using System.Data.SqlClient;

namespace SqlClr
{
    public class StoredProcedures
    {
        public static long last_rowid;
        public static Dictionary<int, long> values = new Dictionary<int, long>();

        [SqlFunction(DataAccess = DataAccessKind.Read, IsDeterministic = false)]
        public static Nullable<long> cached_value(long rowid, int col, Nullable<long> current_value)
        {
            if (rowid < last_rowid)
            {
                values.Clear();
            }

            last_rowid = rowid;

            if (current_value.HasValue)
            {
                values[col] = current_value.Value;
                return current_value.Value;
            }

            if (values.ContainsKey(col))
                return values[col];
            else
                return null;
        }
    }
}

.NET 関数は次のように装飾する必要があることに注意してください。IsDeterministic = false

最後に、25 列の関数を使用した呼び出しの例を次に示します。

SELECT 
dbo.cached_value(id, 1, val1) AS val1,
dbo.cached_value(id, 2, val2) AS val2,
......
dbo.cached_value(id, 25, val25) AS val25
FROM LotsOfValues 

25 列 x 500,000 行に 64 ビット整数と NULL がランダムに入力されるため、実行にselect * from LotsOfValues7 秒かかります。25 列すべての呼び出しを使用するdbo.cached_value(id, n, valn)と、同じクエリに 19 秒かかります。最小 50 列で十分であり、そのうち 25 列はまばらですが、これは 100 の上限までスケーリングされると思います。これはアプリケーションにとって許容できるパフォーマンス ヒットであり、スペースを節約するという目標は達成されました。

于 2013-01-18T06:33:41.717 に答える