4

問題の概要:

Web サービスを使用して複数のデバイスから集中型データベースに収集するデータを記述するデータベース テーブルがあります。

結果を格納するテーブルは、パフォーマンスのために意図的に非正規化されています。複数のインデックスによるクエリとグループ化が高速化されています。 データ アクセスには Entity Framework と Linq を使用しています。

階層的なグループ化とプロジェクションを使用して、 Linq クエリを適切に設計する必要があります。


デバイス データベース モデリングの概要:

現在、私は2種類のデバイスを持っています

1. RFID デバイス

最初のテーブルは、データを収集するタグを記述する RfidTag であり、1 つの RfidTag = 1 つのセンサーです。たとえば、1 つのタグで温度に関するデータを取得できます。

2 番目の表は RfidReader で、添付されたタグからすべてのデータを収集して送信する読み取りモジュールについて説明しています。1 つの RfidReader に添付される RfidTags の数に制限はありません。ただし、読み取り期間中は、1 つの RfidReader に 1 つの RfidTag を付けることができます。

CREATE TABLE [dbo].[RfidTag]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    ReaderId INT NULL,                  -- Reference to reader
    SensorTypeId INT NOT NULL,          -- Reference to sensor type
    SensorParameters NVARCHAR(50) NULL, -- Sensor parameters
    Hex  NVARCHAR(50) NOT NULL,         -- Hex tag identifier stored as string
    Name NVARCHAR(50) NOT NULL,         -- Tag name
    [Description] NVARCHAR(200) NULL,   -- Tag description
    --
)

CREATE TABLE [dbo].[RfidReader]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime  DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    Name        NVARCHAR(20),        -- Tag name
    [Description]   NVARCHAR(200),   -- Tag description                                             
    SerialNumber    NVARCHAR(12),    -- Unique device serial name               
    --
)

各 RfidReaderは、特定の構造について説明されている特定の測定ゾーンに取り付けることができます

CREATE TABLE [dbo].[RfidReaderPlacement]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    --
    ReaderId INT NOT NULL,              -- Reference to Reader.
    MeasurementZoneId INT NOT NULL,     -- Reference to Measurement Zone.
    StartDate DATETIME NOT NULL,        -- Start date of reading.
    StopDate  DATETIME,                 -- End date of reading.
    --
)

RfidTag によって収集された単一のデータは、非正規化されたテーブルに保存されます。このテーブルには何百万ものレコードが格納されており、負荷が非常に高くなっています。このテーブルから、LINQ クエリを使用してデータを収集します。

CREATE TABLE [dbo].[RfidReading]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    ReaderPlacementId INT NOT NULL, -- Reference to Rfid Reader Placement
    ConstructionId  INT NOT NULL,   -- Reference to Construction
    MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone
    ReaderId INT NOT NULL,          -- Reference to Rfid Reader
    TagId    INT NOT NULL,          -- Reference to Rfid Tag
    SensorTypeId INT NOT NULL,      -- Reference to Sensor Type
    ReadingDate DATETIME NOT NULL,  -- Reading date
    Value FLOAT NOT NULL            -- Measured value
    --
)

2. ZigBee デバイス

最初の表は、データを収集する単一のプローブを記述する ZigBeeNodeProbe です。1つの単一の ZigBeeNodeProbe = 1 つの単一のセンサーです。たとえば、1 つのプローブで温度に関するデータを取得できます。

2 番目のテーブルは、接続されたプローブを含む単一のデバイスを説明する ZigBeeNode です。1 つの単一 ZigBeeNode = 3 ZigBeeNodeProbesです。

3 番目の表は、接続されたノードからすべてのデータを収集して送信する読み取りモジュールを説明する ZigBeeReader です。1 つの ZigBeeReader に接続されている (ZigBeeNodeProbe が接続されている) ZigBeeNode の数に制限はありません。ただし、読み取り期間中は、1 つの ZigBeeNode を 1 つの ZigBeeReader に接続できます。

CREATE TABLE [dbo].[ZigBeeNodeProbe]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    --
    NodeId INT NULL,                    -- Reference to node
    SensorTypeId INT NOT NULL,          -- Reference to sensor type
    SensorParameters NVARCHAR(50) NULL, -- Sensor parameters
    SocketNumber  INT NOT NULL,         -- Socket number used in parent ZigBeeNode
    Name NVARCHAR(50) NOT NULL,         -- Node name
    [Description] NVARCHAR(200) NULL,   -- Node description
    --
)

CREATE TABLE [dbo].[ZigBeeNode]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    ReaderId INT NULL,                    -- Reference to reader
    NetworkAddress  NVARCHAR(50) NOT NULL,-- Node address in ZigBee network
    Name NVARCHAR(50) NOT NULL,           -- Given name
    [Description] NVARCHAR(200) NULL,     -- Tag description
    SocketCount INT NOT NULL DEFAULT 0,   -- Count of available sockets to plug in probe
    NodeFrequency INT NULL,               -- Node frequency
)

CREATE TABLE [dbo].[ZigBeeReader]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime  DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    Name        NVARCHAR(20),        -- Tag name
    [Description]   NVARCHAR(200),   -- Tag description                                             
    SerialNumber    NVARCHAR(12),    -- Unique device serial name               
    --
)

各 ZigBeeReaderは、特定の構造について説明されている特定の測定ゾーンに取り付けることができます

CREATE TABLE [dbo].[ZigBeeReaderPlacement]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    --
    ReaderId INT NOT NULL,              -- Reference to Reader.
    MeasurementZoneId INT NOT NULL,     -- Reference to Measurement Zone.
    StartDate DATETIME NOT NULL,        -- Start date of reading.
    StopDate  DATETIME,                 -- End date of reading.
    --
)

ZigBeeNodeProbe によって収集された単一のデータは、非正規化されたテーブルに保存されます。このテーブルには何百万ものレコードが格納されており、負荷が非常に高くなっています。このテーブルから、LINQ クエリを使用してデータを収集します。

CREATE TABLE [dbo].[ZigBeeReading]
(
    Id INT IDENTITY(1,1),
    CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
    ModifiedDateTime DATETIME,
    --
    ReaderPlacementId INT NOT NULL, -- Reference to ZigBee Reader Placement
    ConstructionId    INT NOT NULL, -- Reference to Construction
    MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone
    ReaderId      INT NOT NULL,     -- Reference to ZigBee Reader
    NodeId        INT NOT NULL,     -- Reference to ZigBee Node
    ProbeId       INT NOT NULL,     -- Reference to ZigBee Node Probe
    SensorTypeId      INT NOT NULL, -- Reference to Sensor Type
    ReadingDate   DATETIME NOT NULL,-- Reading date
    Value         FLOAT NOT NULL    -- Measured value
    --
)

クエリ、グループ化、射影の問題:

上記のように、前述の 2 種類のデバイスによって収集されたデータを含む 2 つの分散テーブルがあります。はい、RfidTag は ZigBeeNodeProbe とほぼ同じビジネス モデリングであると想定できます。

RfidReader
-- RFidTag
-- RFidTag
...

ZigBeeReader
-- ZigBeeNode
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
-- ZigBeeNode
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
...

次に、これらの両方のテーブルにクエリを実行し、異なるテーブルの値を同じビュー モデルに射影し、データをフィルター処理するための特定のグループを追加する必要があります。

一般的なシナリオ:

特定の測定ゾーンの平均温度を表すチャートを作成したいのですが、特定の測定ゾーンには複数のリーダー (Rfid と ZigBee の両方) が接続されている可能性があるため、一連のデータを提供する必要があることに注意してください。

有効にしている必要があるHightStock http://www.highcharts.com/products/highstockチャートを使用しています。

  • 1か月、3か月、6か月などのZoom
  • 開始日、終了日
  • 機能のエクスポート
  • シリーズの有効化と無効化の凡例

チャートの例:

http://jsfiddle.net/hNFUY/1/

問題:

階層データの LINQ グループ化と射影クエリを作成する方法は? RfidReading テーブルと ZigBeeReading テーブルの両方に共通のビュー モデルを提供する必要があります。

私の最初の試みは次のようなものでした:

public class ReadingReaderDataModel
{
    public string SeriesName { get; set; }
    public ReadingPeriod ReadingPeriod { get; set; }

    public IEnumerable<ReadingNodeDataModel> ReadingNodeDataModels { get; set; }
    public ReadingReaderDataModel()
    {
        ReadingNodeDataModels = new List<ReadingNodeDataModel>();
    }
}

public class ReadingNodeDataModel
{
    public string NodeName { get; set; }
    public IEnumerable<double> DataValues { get; set; }
    public ReadingNodeDataModel()
    {
        DataValues = new LinkedList<double>();
    }
}

public enum ReadingPeriod
{
    OneMonth, ThreeMonths, SixMonths, YearToDay, OneYear, All
}

public enum ReaderType
{
    Rfid, ZigBee
}

後で、ASP.NET MVC コントローラーの LINQ プロジェクションを設計する必要があります。ここでは、OneMonth、ThreeMonths、SixMonths、YearToDay、OneYear、All でグループ化された期間の平均値を含む必要がある適切なクエリを作成する方法がわかりません。

この高度な LINQ クエリの設計を手伝ってくれる人はいますか?

編集

大規模なデータセットの「推奨事項」を私に指摘しないでください...

これはパフォーマンスの問題ではありません。

この質問は、複雑な LINQ クエリに関するものです。私は適切なLINQコードを探していますが、「その車は速いので、その車を使用する必要があります」などの回答ではありません...コードの回答をお願いします...シナリオを理解しようとせず、コードを提供しない場合は、しないでください参加...

この質問の主題のように高度なLINQの質問であるため、LINQの解決策を見つけるために特別に報奨金を追加しました。

4

1 に答える 1

6

私が理解しているように、データベースには何百万ものレコードがあり、アプリケーションから非常に優れたパフォーマンスが必要であり、非常に複雑な構造になっています。

EFに近づかないでください。小さなデータセットに使用できますが、巨大なクエリから優れたパフォーマンスを必要とするものについては、そこに行かないでください。

私の提案は、クエリを手動で作成することです。EFを使用して可能な限り最適化する場合、とにかく多くのコードをスキップすることは実質的に不可能であり、基本的にLINQの方法でSQLを作成する(つまり、すべてのSELECTステートメントを指定する)ためです。 。

もう少し具体的にしたい場合は、Dapperを使用してください。StackOverflowを実行するのは「ORM」です。ここに速度の比較があります:http ://code.google.com/p/dapper-dot-net/

ただし、EFの使用に完全に取り掛かっている場合は...

1つのクエリを作成しようとしないでください。それは起こりません。代わりに、それらを分割します。あなたが作る必要があるグループごとに異なるものを取りなさい。それははるかに簡単な方法です。1つのグループだけを取り出すためのLINQクエリがすでにあるはずです。ここで、必要な他のすべてのグループでこれを繰り返します。特に、WhereとOrderByが大量に含まれている場合はそうです。

出典:毎日大規模なデータセットクエリを処理する人。

于 2012-06-10T15:58:34.063 に答える