当密钥在范围内而不是单个值时,如何记忆或存储密钥值对?

时间:2016-04-07 18:12:50

标签: c# .net memcached enyim

我们的数据库中有一个表,其中包含静态IP范围的城市及其IP地址。它看起来像:

IP-TO,IP-FROM,CITY

100,110,A

111,168,B

...

965,1000,Z

我提到了样本数据。实际数据非常庞大,表格中有近64k行。

对于我们网站上的每个用户,我们通过在sql express服务器上执行sql查询来确定他们的IP地址。

由于数据是静态的,例如IP在100到110范围内的每个用户都属于城市A,我们每次都会不必要地访问数据库。

我们正在考虑缓存每次独特的ip访问。例如: IP-100映射到A IP-101映射到A ... IP-110映射到A

但这会在memcache中创建64k密钥,我觉得当我们知道范围时,没有必要存储多个具有相同值的密钥。

我们能以某种方式以更好的方式做到这一点,即通过最小的mem缓存密钥或完全使用不同的方法吗?

3 个答案:

答案 0 :(得分:0)

可以对IP地址列表进行排序(因为它们本质上是数字)。如果您有一个很大的非重叠IP​​范围列表,则可以将它们排序为一个大列表。如果您有一个很大的排序值列表,则可以对其执行binary search。使用64k项目,您可以在大约16个比较中搜索整个列表(几乎是即时的)。

使用正确的索引和查询,您的数据库可能能够为您执行此操作。如果您认为它可以更快的另一种方式(提示:使用分析来确定它是否真的!)或者担心额外的数据库访问,您可以将整个表的数据缓存在内存中,并搜索名单。从高层来看:

public class IPRangeCache
{
    private List<IPRangeRecord> sortedRangeRecords = null; // get from database

    public string GetCity(IPAddress ip) {
        // binary search to find from sortedRangeRecords
    }
}

二进制搜索需要考虑开始和结束数字。自定义比较器或自定义二进制搜索应该可以做到这一点。这应该非常快。

您也可以尝试缓存最后几分钟&#39;字典中的IP地址价值,但我认为它不可能更快。

答案 1 :(得分:0)

我们可以使用C#通用字典。

我们创建一个包含IP范围的类。这个类将作为字典的关键。

class IP_Range 
{
    public int MinIP { get; set; }
    public int MaxIP { get; set; }
}

然后我们必须创建一个比较器类,它将有助于比较字典的键。

class IP_RangeComparer : IEqualityComparer<IP_Range>
{
    public bool Equals(IP_Range r1, IP_Range r2)
    {
        return (r1.MinIP == r2.MinIP && r1.MaxIP == r2.MaxIP);
    }

    public int GetHashCode(IP_Range r)
    {
        return r.MinIP.GetHashCode();
    }
}

然后我们可以创建一个通用字典并使用它如下:

IDictionary<IP_Range, string> myCache = new Dictionary<IP_Range, string>(new IP_RangeComparer());

// Adding entries
myCache.Add(new IP_Range() { MinIP = 100, MaxIP = 110 }, "A");
myCache.Add(new IP_Range() { MinIP = 111, MaxIP = 168 }, "B");
myCache.Add(new IP_Range() { MinIP = 169, MaxIP = 200 }, "C");

// Reading the dictionary
string city = myCache[new IP_Range() { MinIP = 169, MaxIP = 200 }];

有关详细说明,请参阅this article

注意:要找出您要搜索的特定IP的密钥,您必须遍历myCache.Keys集合。

答案 2 :(得分:0)

您可以创建IpAddressfrom the value的实例,然后仅使用one of the bytes作为缓存键。这样你只需要一次到001.xxx.xxx.xxx的数据库,一次用于002.xxx.xxx.xxx等。

var address = new IPAddress(value);
var bytes = address.GetAddressBytes(); //an array of four bytes