我必须从数据库中检索以下结构:
User ID
User Name
First Name
Last Name
Employee Number
这些字段我将它们存储在内存中以便快速访问,换句话说就是缓存。我们平均在谈论300,000条记录。
我的问题是我必须创建一个结构,以便有时通过用户名快速查询,有时还可以通过员工编号进行快速查询。绝不是用户ID,只能通过上述两个字段。
在字典中,我受限于唯一的一键原则,所以......
- 有没有办法创建一个将用户名和员工号结合起来用于词典的键?
这里的问题是,有时我将使用用户提供的用户名进行查找,有时候我会有员工编号,但不会同时使用。
所以这个密钥,让我们说MyKey(“用户名”,“”)和MyKey(“”,“employee-number”)应该从地图中检索相同的注册表。
我想避免在内存中创建两个词典,一个用于搜索用户名,另一个用于通过员工编号进行搜索?
另一种方法是将数据库中的结果存储在一个大列表中,然后使用Linq进行查询。然而,这将是对O(n)的搜索,我们在这里谈论性能。
答案 0 :(得分:0)
您有以下选择:
选择可能取决于在典型情况下测试每个解决方案。它需要来实验的努力。
答案 1 :(得分:0)
所以我解决了创建一个带有Type和Value的Key对象的问题。
/// <summary>
/// Represents a composite key for cached objects
/// </summary>
public class MultiKey
{
/// <summary>
/// The type of key
/// </summary>
public enum Type
{
/// <summary>
/// The key represents a User Name
/// </summary>
UserName,
/// <summary>
/// The key represents an Employee Number
/// </summary>
EmployeeNumber
}
/// <summary>
/// Gets or sets the Type of the Key.
/// </summary>
public Type KeyType { get; set; }
/// <summary>
/// Gets or sets the value of the Key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Compare based on hash code
/// </summary>
/// <param name="obj">the object to compare against</param>
/// <returns>true if both objects are equals, false otherwise</returns>
public override bool Equals(object obj)
{
if (obj is FormCacheKey)
{
return (obj as FormCacheKey).GetHashCode() == this.GetHashCode();
}
return false;
}
/// <summary>
/// Compares based on hash code
/// </summary>
/// <param name="p1">left side of the operator</param>
/// <param name="p2">right side of the operator</param>
/// <returns>true if both items are equal, false otherwise</returns>
public static bool operator ==(FormCacheKey p1, FormCacheKey p2)
{
if ((object)p1 == null && (object)p2 == null)
{
return true;
}
if ((object)p1 == null || (object)p2 == null)
{
return false;
}
return p1.Equals(p2);
}
/// <summary>
/// Compares based on hash code
/// </summary>
/// <param name="p1">left side of the operator</param>
/// <param name="p2">right side of the operator</param>
/// <returns>true if both items are different, false otherwise</returns>
public static bool operator !=(FormCacheKey p1, FormCacheKey p2)
{
return !(p1 == p2);
}
/// <summary>
/// Returns a hash key code that identifies this object
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
const int CoPrimeNumber = 37;
var finalHashCode = 17;
finalHashCode = (finalHashCode * CoPrimeNumber) + this.KeyType.GetHashCode();
finalHashCode = (finalHashCode * CoPrimeNumber) + this.Key.GetHashCode();
return finalHashCode;
}
}
之后我创建了一个像
这样的字典var cache = new Dictionary<MultiKey, User>();
最后我将我的键和值添加到字典中,如下所示:
foreach (var user in users)
{
var userNameKey = new MultiKey { KeyType = MultiKey.Type.UserName, Key = user.UserName };
cache.Add(userNameKey, user);
var employeeNumberKey = new MultiKey { KeyType = MultiKey.Type.EmployeeNumber, Key = user.EmployeeNumber };
cache.Add(employeeNumberKey, user);
}
有关效果的说明 与同事交谈,他正在捍卫两种哈希表技术,而不是我使用MultiKey的方法。他认为在搜索(访问)期间使用两个特殊哈希值中的字符串键的性能更快&#39;或者“性能更高”&#39;而不是具有复杂密钥的单个缓存。他的论点是,当缓存更大/更复杂时,碰撞往往会发生更多。我想听听你的意见。最后我使用了这种方法并且有效。
要访问cahe中的项目,必须提供MultiKey对象或重新创建它的方法。从这个意义上讲,我创建了以下辅助方法
private T GetFromCache<T>(CacheKey.Type type, string key)
{
var cKey = new MultiKey { KeyType = type, Key = key };
T item;
cache.TryGetValue(cKey, out item);
return item;
}
我这样使用它:
public User GetUserByUserName(string userName)
{
return this.GetFromDictionary<User>(MultiKey.Type.UserName, userName);
}
public User GetIndividualByEmployeeNumber(string employeeNumber)
{
return this.GetFromDictionary<User>(MultiKey.Type.EmployeeNumber, employeeNumber);
}