程式千萬筆資料量級搜尋提速方式

千萬筆資料要怎麼讓每次搜尋的速度提升呢?
我以前一直蠻好奇的,最近有幸理解到一個簡單理解的做法。

用C#舉例,如下程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;

namespace LargeData
{
public class OrderModel
{
public string OrderNumber { get; set; }
}
public class Program
{
private static readonly int _dataCount = 20000000;
public static void Main()
{
var list = new List<OrderModel>();
for (var i = 0; i < _dataCount; i++)
{
list.Add(new OrderModel
{
OrderNumber = $"{i + 1}"
});
}

Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();

var result = list.ToList();
var targetOrderNumber = "20000000";
var targetOrder = list
.Where(x => x.OrderNumber == targetOrderNumber)
.FirstOrDefault();

Console.WriteLine($"TargetOrder:{targetOrder.OrderNumber}");

sw.Stop();
string second = (sw.Elapsed.TotalMilliseconds / 1000).ToString();
Console.WriteLine($"Run:{second}");
}
}
}

output:

1
2
TargetOrder:20000000
Run Second:0.89836

如上,在2千萬筆資料中查詢只耗了0.8秒。

簡單來說就是靠快取,我們將17~24行的資料儲存到記憶體中或是其他Redis伺服器當作快取。
每次在程式中去撈取時只要從該入口去提取資料即可,雖然耗費記憶體,但提速效果極高。
這作法前提:當資料異動時需同步更新快取資料,必須做好單一入口去做存取。

在30~34行中,我們可以使用演算法去優化,在這裡用最簡單的O(n)作法,如果有使用如二元樹搜尋那可以最佳化到O(log n),最差O(n)。

我在執行以上的程式使用了2.4G記憶體。

電腦效能:

  • Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz 2.81 GHz
  • 16.0 GB (15.9 GB usable)

如果把這個快取資料放到其他伺服器做,那記憶體在程式上就幾乎不占記憶體。
把記憶體耗損轉移到其他伺服器上,記憶體不足時也只要去擴增快取伺服器的記憶體。

結論

算是有點火影忍者卡卡西萬花筒血輪眼神威的作法,把負載轉移到其他空間的快取。