데이터베이스에서 다음 구조를 검색해야합니다.
User ID
User Name
First Name
Last Name
Employee Number
이 필드는 빠른 액세스를 위해 메모리, 즉 캐시에 저장합니다. 평균적으로 약 300,000 개의 레코드를 이야기하고 있습니다.
내 문제는 때때로 사용자 이름과 직원 번호로 빠른 쿼리를위한 구조를 만들어야한다는 것입니다. 사용자 ID로는 절대 사용하지 말고 앞서 언급 한 두 필드 만 사용하세요.
사전에서 나는 유일한 핵심 원칙에 묶여 있으므로 ...
-사전에서 사용하기 위해 사용자 이름과 직원 번호를 결합한 키를 만드는 방법이 있습니까?
여기서 문제는 때때로 사용자가 조회를 위해 사용자 이름을 제공하고 때로는 직원 번호를 가지지 만 동시에 둘 다 가질 수 없다는 것입니다.
따라서이 키는 MyKey ( "user-name", "") 및 MyKey ( "", "employee-number")가 맵에서 동일한 레지스트리를 검색해야한다고 가정합니다.
메모리에 두 개의 사전을 만드는 것을 피하고 싶습니다. 하나는 사용자 이름으로 검색하고 다른 하나는 직원 번호로 검색합니까?
대안은 DB의 결과를 큰 목록에 저장 한 다음 Linq로 쿼리하는 것입니다. 그러나 이것은 O (n) 검색이 될 것이며 여기서 성능에 대해 이야기하고 있습니다.
그래서 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에서 사용한 접근 방식 대신 두 개의 해시 테이블 기술을 옹호하고있었습니다. 그는 두 개의 창 모양 해시에서 문자열 키를 사용하는 검색 (액세스) 중 성능이 복잡한 키가있는 단일 캐시보다 '빠르거나' '성능이 높다'고 주장했습니다. 그의 주장은 캐시가 더 크고 복잡 할 때 충돌이 더 많이 발생하는 경향이 있다는 것입니다. 여러분의 의견을 듣고 싶습니다. 결국 나는이 접근 방식을 사용했고 작동합니다.
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);
}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다