【实战】提升List性能方法有几何

在内存中的 List<T> 上使用 LINQ 查询时,加索引并不像数据库那样有内置支持,但可以通过以下方式提高查询性能:


1. 手动构建索引

可以手动构建一个字典 (Dictionary<TKey, TValue>),将需要查询的字段作为键,值为对应的数据。查询时直接利用字典的 O(1) 查找性能。

示例代码:
csharp 复制代码
// 假设有一个类
public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// 构建索引
var employees = new List<Employee>
{
    new Employee { Id = 1, Name = "Alice" },
    new Employee { Id = 2, Name = "Bob" },
    new Employee { Id = 3, Name = "Charlie" }
};

// 创建索引
var employeeIndex = employees.ToDictionary(e => e.Id, e => e);

// 查询时使用索引
int searchId = 2;
if (employeeIndex.TryGetValue(searchId, out var employee))
{
    Console.WriteLine($"Found: {employee.Name}");
}
else
{
    Console.WriteLine("Not Found");
}

2. 预先分组以提高查询性能

对于需要多次按某个字段查询的场景,可以使用 Lookup<TKey, TElement> 预分组数据。Lookup 类似于 Dictionary,但支持一个键对应多个值。

示例代码:
csharp 复制代码
// 构建分组索引
var employeeLookup = employees.ToLookup(e => e.Name);

// 按 Name 查询
string searchName = "Alice";
foreach (var emp in employeeLookup[searchName])
{
    Console.WriteLine($"Found: {emp.Name} with Id: {emp.Id}");
}

3. 自定义数据结构

如果查询条件多样化,可以构建多字段索引,类似于复合索引。

示例代码:
csharp 复制代码
// 复合索引
var compositeIndex = employees.ToDictionary(e => (e.Id, e.Name), e => e);

// 查询
var key = (Id: 1, Name: "Alice");
if (compositeIndex.TryGetValue(key, out var result))
{
    Console.WriteLine($"Found: {result.Name}");
}

4. 排序后使用二分查找

如果 List<T> 是按查询字段排序的,可以使用 BinarySearch 来快速查找。

示例代码:
csharp 复制代码
// 排序列表
employees = employees.OrderBy(e => e.Id).ToList();

// 二分查找
int searchId = 2;
var found = employees.BinarySearch(
    new Employee { Id = searchId },
    Comparer<Employee>.Create((x, y) => x.Id.CompareTo(y.Id))
);

if (found >= 0)
{
    Console.WriteLine($"Found: {employees[found].Name}");
}
else
{
    Console.WriteLine("Not Found");
}

5. 使用缓存优化查询

如果查询是频繁且集中在某些字段上,可以构建一个缓存层,例如使用 MemoryCache

示例代码:
csharp 复制代码
using System.Runtime.Caching;

// 创建缓存
var cache = MemoryCache.Default;
string cacheKey = "EmployeeById";
cache[cacheKey] = employeeIndex; // 使用之前构建的字典

// 查询缓存
if (cache.Contains(cacheKey))
{
    var cachedIndex = (Dictionary<int, Employee>)cache[cacheKey];
    if (cachedIndex.TryGetValue(2, out var cachedEmployee))
    {
        Console.WriteLine($"From Cache: {cachedEmployee.Name}");
    }
}

6. 结合并行查询

对于大规模数据,可以结合并行 LINQ (PLINQ) 提高查询速度。

示例代码:
csharp 复制代码
// 使用 PLINQ
var result = employees.AsParallel()
    .Where(e => e.Name.StartsWith("A"))
    .ToList();

foreach (var emp in result)
{
    Console.WriteLine($"Found: {emp.Name}");
}

总结

加索引的方法需要根据具体场景选择:

  • 如果查询频繁,使用 DictionaryLookup
  • 如果是多字段组合查询,构建复合索引。
  • 如果数据较多且一次性查询,考虑使用排序加二分查找。
  • 对于性能要求极高的场景,可以结合缓存或并行查询优化。

根据你的需求,可以选用其中一个或多个组合方式。

相关推荐
向夏威夷 梦断明暄8 小时前
C# 弃元模式:从语法糖到性能利器的深度解析
服务器·数据库·c#
rick9779 小时前
C# × Python 互操不再难:DotNetPy 让两大生态真正融合
c#
ellis197010 小时前
C#/Unity清理非托管资源
unity·c#
吴可可1231 天前
C#用OpenCVSharp提取轮廓生成CAD多段线
c#
制造数据与AI践行者老蒋1 天前
离谱!PromptTemplate 遇上 JSON,花括号直接引发解析战争
数据库·microsoft·json
玖玥拾1 天前
Unity 3D 笔记(十四)Unity/C# Socket 网络笔记3
服务器·网络·unity·c#
行者-全栈开发1 天前
CVE-2026-45659:Microsoft SharePoint远程代码执行漏洞深度解析与修复指南
microsoft·sharepoint·反序列化·运维自动化·安全修复·远程代码执行·cve-2026-45659
玖玥拾1 天前
Unity 3D 笔记(十七)Unity/C# Socket 网络笔记6
服务器·网络·unity·c#
geovindu1 天前
CSharp: Iterative Algorithms
开发语言·后端·算法·c#·.net·迭代算法
影寂ldy1 天前
C# HttpClient 分片下载、断点续传、暂停取消(完整项目知识点)
开发语言·c#