C# 實現列式存儲數據

C#實現列式存儲數據指南

一、列式存儲概述

列式存儲(Columnar Storage)是一種數據存儲方式,它將數據按列而非行組織。與傳統的行式存儲相比,列式存儲在以下場景具有優勢:

  1. ??分析型查詢??:聚合計算、分組統計等操作效率更高
  2. ??壓縮率更高??:相同數據列式存儲通常占用更少空間
  3. ??I/O效率更高??:只需讀取相關列的數據

二、C#實現列式存儲方案

方案1:使用數組實現簡單列式存儲

public class ColumnarStorage<T>
{private readonly List<List<T>> _columns = new List<List<T>>();private readonly Dictionary<string, int> _columnIndexes = new Dictionary<string, int>();public void AddColumn(string columnName, IEnumerable<T> values){if (_columnIndexes.ContainsKey(columnName))throw new ArgumentException($"Column '{columnName}' already exists");var column = values.ToList();_columns.Add(column);_columnIndexes[columnName] = _columns.Count - 1;}public void AddRow(IEnumerable<T> values){if (values.Count() != _columns.Count)throw new ArgumentException("Number of values doesn't match number of columns");for (int i = 0; i < values.Count(); i++){_columns[i].Add(values.ElementAt(i));}}public IEnumerable<T> GetColumn(string columnName){if (!_columnIndexes.TryGetValue(columnName, out int index))throw new ArgumentException($"Column '{columnName}' not found");return _columns[index];}public IEnumerable<T> GetRow(int rowIndex){return _columns.Select(c => c[rowIndex]);}// 其他方法如查詢、聚合等...
}

??使用示例??:

var storage = new ColumnarStorage<int>();
storage.AddColumn("ID", new List<int> { 1, 2, 3 });
storage.AddColumn("Value", new List<int> { 10, 20, 30 });// 添加行(不推薦,因為列式存儲通常先定義列再填充數據)
// storage.AddRow(new List<int> { 4, 40 });// 查詢
var values = storage.GetColumn("Value"); // 返回 [10, 20, 30]

方案2:使用專業列式存儲庫 - Parquet.NET

??安裝NuGet包??:

dotnet add package Parquet.Net

??實現示例??:

using Parquet;
using Parquet.Data;// 創建數據字段
var fields = new[]
{new DataField<int>("id"),new DataField<string>("name"),new DataField<double>("value")
};// 創建數據集
var dataSet = new DataSet(fields)
{new Row(1, "Item1", 10.5),new Row(2, "Item2", 20.3),new Row(3, "Item3", 30.7)
};// 寫入Parquet文件
using (var stream = File.Create("data.parquet"))
{ParquetWriter.WriteFile(dataSet, stream);
}// 讀取Parquet文件
using (var stream = File.OpenRead("data.parquet"))
{var reader = new ParquetReader(stream);var ds = reader.ReadDataSet();foreach (var row in ds[0]){Console.WriteLine($"{row[0]} {row[1]} {row[2]}");}
}

方案3:使用內存列式存儲 - Apache Arrow

??安裝NuGet包??:

dotnet add package Apache.Arrow

??實現示例??:

using Apache.Arrow;
using Apache.Arrow.Arrays;// 創建列
var idColumn = new Int32Array.Builder().Append(1).Append(2).Append(3).Build();var nameColumn = new BinaryArray.Builder(BinaryArrayBuilderOptions.Default).Append("Item1").Append("Item2").Append("Item3").Build();var valueColumn = new DoubleArray.Builder().Append(10.5).Append(20.3).Append(30.7).Build();// 創建表
var schema = new Schema(new[]
{new Field("id", new Int32Type()),new Field("name", new BinaryType()),new Field("value", new DoubleType())
});var table = new Table(schema, new[] { idColumn, nameColumn, valueColumn });// 序列化為Arrow格式
using (var stream = File.Create("data.arrow"))
{var writer = new ArrowStreamWriter(table, new MessageSerializer(), stream);writer.WriteTable(table);writer.Dispose();
}// 從Arrow文件讀取
using (var stream = File.OpenRead("data.arrow"))
{var reader = new ArrowStreamReader(stream);var table = reader.ReadNextTable();foreach (var row in table.ToEnumerable()){Console.WriteLine($"{row[0]} {row[1]} {row[2]}");}
}

三、列式存儲優化技巧

1. 數據壓縮

??使用Parquet的壓縮選項??:

var writerProperties = new WriterProperties(CompressionCodec.Snappy // 使用Snappy壓縮
);using (var stream = File.Create("compressed.parquet"))
{ParquetWriter.WriteFile(dataSet, stream, writerProperties);
}

2. 列式查詢優化

??實現列式索引??:

public class ColumnIndex<T>
{private readonly Dictionary<T, List<int>> _index = new Dictionary<T, List<int>>();public void Build(IEnumerable<T> column){int rowIndex = 0;foreach (var value in column){if (!_index.ContainsKey(value))_index[value] = new List<int>();_index[value].Add(rowIndex++);}}public IEnumerable<int> Lookup(T value){return _index.TryGetValue(value, out var rows) ? rows : Enumerable.Empty<int>();}
}

3. 內存映射文件

??使用MemoryMappedFile處理大文件??:

using var mmf = MemoryMappedFile.CreateFromFile("large.parquet");
using var accessor = mmf.CreateViewAccessor();// 直接訪問文件中的特定列數據

四、完整示例:實現簡單的列式數據庫

public class ColumnarDatabase
{private readonly Dictionary<string, List<object>> _columns = new();private readonly Dictionary<string, Type> _columnTypes = new();public void CreateTable(IEnumerable<string> columnNames, IEnumerable<Type> columnTypes){if (columnNames.Count() != columnTypes.Count())throw new ArgumentException("Column names and types count mismatch");for (int i = 0; i < columnNames.Count(); i++){_columns[columnNames.ElementAt(i)] = new List<object>();_columnTypes[columnNames.ElementAt(i)] = columnTypes.ElementAt(i);}}public void InsertRow(IEnumerable<object> values){if (values.Count() != _columns.Count)throw new ArgumentException("Values count doesn't match columns count");var enumerators = values.GetEnumerator();foreach (var column in _columns.Values){enumerators.MoveNext();column.Add(enumerators.Current);}}public IEnumerable<object> GetColumn(string columnName){return _columns[columnName];}public IEnumerable<object[]> GetRowsWhere(string columnName, object value){var columnIndex = _columns.Keys.ToList().IndexOf(columnName);if (columnIndex == -1) yield break;var column = _columns.Values.ElementAt(columnIndex);var indexes = new ColumnIndex<object>().Build(column).Where(kvp => kvp.Key.Equals(value)).SelectMany(kvp => kvp.Value);for (int i = 0; i < column.Count; i++){if (indexes.Contains(i)){yield return _columns.Values.Select(c => c[i]).ToArray();}}}// 更多方法...
}

五、性能對比測試

??測試代碼??:

var columnar = new ColumnarStorage<int>();
var rowBased = new List<List<int>>();// 填充100萬行數據
var sw = Stopwatch.StartNew();
for (int i = 0; i < 1_000_000; i++)
{columnar.AddColumn("ID", new List<int> { i });columnar.AddColumn("Value", new List<int> { i * 2 });// 行式存儲(僅演示,實際不推薦這樣使用)if (i == 0) rowBased.Add(new List<int>());rowBased[0].Add(i);rowBased[0].Add(i * 2);
}
sw.Stop();
Console.WriteLine($"填充時間: {sw.ElapsedMilliseconds}ms");// 查詢測試
sw.Restart();
var columnarValues = columnar.GetColumn("Value");
sw.Stop();
Console.WriteLine($"列式查詢時間: {sw.ElapsedMilliseconds}ms");sw.Restart();
var rowBasedValues = rowBased.SelectMany(r => r).Where((v, i) => i % 2 == 1); // 模擬查詢第二列
sw.Stop();
Console.WriteLine($"行式查詢時間: {sw.ElapsedMilliseconds}ms");

??預期結果??:

  • 列式存儲在查詢特定列時性能更好
  • 行式存儲在插入時可能更快(但實際列式存儲優化后插入也很快)

六、實際應用場景

  1. ??數據分析平臺??:

    • 處理TB級數據
    • 高效聚合計算
    • 列式壓縮節省存儲空間
  2. ??商業智能工具??:

    • 快速生成報表
    • 復雜查詢優化
    • 多維分析支持
  3. ??時序數據處理??:

    • 高效存儲時間序列數據
    • 快速聚合計算
    • 支持降采樣查詢

七、擴展建議

  1. ??實現列式壓縮??:

    public byte[] CompressColumn<T>(List<T> column)
    {using var ms = new MemoryStream();using (var writer = new BinaryWriter(ms)){foreach (var item in column){// 實現自定義壓縮邏輯writer.Write(item.ToString());}}return ms.ToArray();
    }
  2. ??添加索引支持??:

    public class ColumnIndex
    {private readonly Dictionary<object, List<int>> _valueToRows = new();public void Build<T>(List<T> column){for (int i = 0; i < column.Count; i++){if (!_valueToRows.ContainsKey(column[i]))_valueToRows[column[i]] = new List<int>();_valueToRows[column[i]].Add(i);}}public IEnumerable<int> GetRows(T value) => _valueToRows.TryGetValue(value, out var rows) ? rows : Enumerable.Empty<int>();
    }
  3. ??支持列式存儲格式??:

    • Parquet
    • ORC
    • Apache Arrow
    • 自定義二進制格式

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77923.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77923.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77923.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mysql索引分類、索引失效場景

索引分類 按數據結構分類? B-Tree索引&#xff08;BTree&#xff09; 描述??&#xff1a;默認的索引類型&#xff0c;大多數存儲引擎&#xff08;如InnoDB、MyISAM&#xff09;支持。實際使用BTree結構&#xff0c;數據存儲在葉子節點&#xff0c;葉子節點通過指針連接&a…

SpringBoot+Redis全局唯一ID生成器

&#x1f4e6; 優雅版 Redis ID 生成器工具類 支持&#xff1a; 項目啟動時自動初始化起始值獲取自增 ID 方法yml 配置化起始值可靈活擴展多業務線 ID &#x1f4cc; application.yml 配置 id-generator:member-start-value: 1000000000&#x1f4cc; 配置類&#xff1a;IdG…

深入掌握CSS背景圖片:從基礎到實戰

背景圖片&#xff1a; 本文將通過系統化的講解實戰案例&#xff0c;幫助讀者徹底掌握CSS背景圖片的六大核心知識點。每個知識點都包含對比演示和記憶技巧&#xff0c;建議結合代碼實操學習。 一、背景圖片基礎設置 使用background-image&#xff08;路徑&#xff09;屬性設置…

WPF之XAML基礎

文章目錄 XAML基礎&#xff1a;深入理解WPF和UWP應用開發的核心語言1. XAML簡介XAML與XML的關系 2. XAML語法基礎元素語法屬性語法集合語法附加屬性 3. XAML命名空間命名空間映射關系 4. XAML標記擴展靜態資源引用數據綁定相對資源引用常見標記擴展對比 5. XAML與代碼的關系XAM…

驅動車輛診斷測試創新 | 支持診斷測試的模擬器及數據文件轉換生成

一 背景和挑戰 | 背景&#xff1a; 隨著汽車功能的日益豐富&#xff0c;ECU和域控制器的復雜性大大增加&#xff0c;導致測試需求大幅上升&#xff0c;尤其是在ECU的故障診斷和性能驗證方面。然而&#xff0c;傳統的實車測試方法難以滿足高頻率迭代和驗證需求&#xff0c;不僅…

免疫細胞靶點“破局戰”:從抗體到CAR-T,自免疾病治療的3大技術突破

引言 人體免疫系統組成了一個嚴密調控的“網絡”&#xff0c;時刻檢測著外來病原體&#xff0c;并將其與自身抗原區分開來。但免疫系統也可能會被“策反”&#xff0c;錯誤的攻擊我們自身&#xff0c;從而導致自身免疫性疾病的發生。 目前已知的自免疾病超過100種&#xff0c…

計算機網絡應用層(5)-- P2P文件分發視頻流和內容分發網

&#x1f493;個人主頁&#xff1a;mooridy &#x1f493;專欄地址&#xff1a;《計算機網絡&#xff1a;自頂向下方法》 大綱式閱讀筆記_mooridy的博客-CSDN博客 &#x1f493;本博客內容為《計算機網絡&#xff1a;自頂向下方法》第二章應用層第五、六節知識梳理 關注我&…

十二種存儲器綜合對比——《器件手冊--存儲器》

存儲器 名稱 特點 用途 EEPROM 可電擦除可編程只讀存儲器&#xff0c;支持按字節擦除和寫入操作&#xff0c;具有非易失性&#xff0c;斷電后數據不丟失。 常用于存儲少量需要頻繁更新的數據&#xff0c;如設備配置參數、用戶設置等。 NOR FLASH 支持按字節隨機訪問&…

第十六屆藍橋杯 2025 C/C++組 旗幟

目錄 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; 思路&#xff1a; 思路詳解&#xff1a; 代碼&#xff1a; 代碼詳解&#xff1a; 題目&#xff1a; 題目描述&#xff1a; 題目鏈接&#xff1a; P12340 [藍橋杯 2025 省 AB/Python B 第二場] 旗幟 -…

比亞迪再獲國際雙獎 以“技術為王”書寫中國汽車出海新篇章

近日&#xff0c;全球汽車行業權威獎項“2025世界汽車大獎”&#xff08;World Car Awards&#xff09;在紐約國際車展舉行頒獎典禮&#xff0c;比亞迪海鷗&#xff08;BYD SEAGULL/BYD DOLPHIN MINI&#xff09;摘得“2025世界城市車&#xff08;World Urban Car&#xff09;”…

人工智能數學基礎(五):概率論

概率論是人工智能中處理不確定性的核心工具&#xff0c;它為機器學習、數據科學和統計分析提供了理論基礎。本文將深入淺出地介紹概率論的重要概念&#xff0c;并結合 Python 實例&#xff0c;幫助讀者更好地理解和應用這些知識。資源綁定附上完整資源供讀者參考學習&#xff0…

MCP協議:自然語言與結構化數據的雙向橋梁 ——基于JSON-RPC 2.0的標準化實踐

MCP協議&#xff1a;自然語言與結構化數據的雙向橋梁 ——基于JSON-RPC 2.0的標準化實踐 一、MCP的本質&#xff1a;標準化共識的協議框架 MCP&#xff08;Model Context Protocol&#xff09;是Anthropic于2024年提出的開放通信協議&#xff0c;其核心價值在于建立自然語言…

vue+django農產品價格預測和推薦可視化系統[帶知識圖譜]

文章結尾部分有CSDN官方提供的學長 聯系方式名片 文章結尾部分有CSDN官方提供的學長 聯系方式名片 關注B站&#xff0c;有好處&#xff01; ?編號&#xff1a;D010 vue django 前后端分離架構搭建的系統帶有推薦算法、價格預測、可視化、知識圖譜數據從爬蟲獲取可以更新到最…

verilog_testbench技巧

forever語句 forever begin state; end 一直執行state repeat&#xff08;n&#xff09; begin state; end 執行state&#xff0c;n次 force語句對雙向端口進行輸入賦值。 與wait 是邊沿觸發&#xff0c;wait是電平觸發 仿真控制語句與系統任務描述 $stop停止仿真…

實時時鐘(RTC)從原理到實戰

1. RTC技術深度解析 1.1 RTC核心概念 實時時鐘&#xff08;Real-Time Clock&#xff0c;RTC&#xff09;是嵌入式系統中獨立于主處理器的特殊計時電路&#xff0c;其核心功能在于提供持續可靠的時間基準。與CPU時鐘不同&#xff0c;RTC具有以下關鍵特性&#xff1a; 獨立供電…

pyspark將hive數據寫入Excel文件中

不多解釋直接上代碼&#xff0c;少python包的自己直接下載 #!/usr/bin/env python # -*- encoding: utf-8 -*- from pyspark.sql import SparkSession import pandas as pd import os# 初始化 SparkSession 并啟用 Hive 支持 spark SparkSession.builder \.appName("sel…

Stack--Queue 棧和隊列

一、Stack--棧 1.1 什么是棧&#xff1f; 堆棧是一種容器適配器&#xff0c;專門設計用于在 LIFO 上下文&#xff08;后進先出&#xff09;中運行&#xff0c;其中元素僅從容器的一端插入和提取。 第一個模版參數T&#xff1a;元素的類型&#xff1b;第二個模版參數Container…

用Python做有趣的AI項目1:用 TensorFlow 實現圖像分類(識別貓、狗、汽車等)

項目目標 通過構建卷積神經網絡&#xff08;CNN&#xff09;&#xff0c;讓模型學會識別圖片中是什么物體。我們將使用 CIFAR-10 數據集&#xff0c;它包含 10 類&#xff1a;飛機、汽車、鳥、貓、鹿、狗、青蛙、馬、船和卡車。 &#x1f6e0;? 開發環境與依賴 安裝依賴&…

3D可視化編輯器模版

體驗地址&#xff1a;http://mute.turntip.cn 整個搭建平臺核心模塊包含如下幾個部分&#xff1a; 3D場景渲染 組件拖拽系統 元素編輯功能 狀態管理 歷史記錄與撤銷/重做 技術棧 前端框架與庫 React 18 用于構建用戶界面的JavaScript庫 Next.js 14 React框架&#xff0c;提供服…

“連接世界的橋梁:深入理解計算機網絡應用層”

一、引言 當你瀏覽網頁、發送郵件、聊天或觀看視頻時&#xff0c;這一切都離不開計算機網絡中的應用層&#xff08;Application Layer&#xff09;。 應用層是網絡協議棧的最頂層&#xff0c;直接為用戶的各種應用程序提供服務。它為用戶進程之間建立通信橋梁&#xff0c;屏蔽了…