자동 정렬과 호환되는 LINQ 쿼리의 리턴 유형에 관한 성능
-
21-09-2019 - |
문제
이것은 실제로 문제가 아니지만 제발 입력을 주셔서 감사합니다.
winforms c# .NET3.5 [SP1] Visual Studio 2008 Linq2SQL 사용 (보다 구체적으로 plinqo... 환상적인 btw!). +/- 19000 행의 데이터를 반환하는 결과 세트가 있으며 (행당 약 804 년 정도의 데이터 포함) 데이터 검색 메소드를 백그라운드로 푸시하고 그에 따라 UI를 업데이트하기로 결정했습니다. 이것은 잘 작동합니다.
그러나 Ling 데이터 검색 방법에 다른 리턴 유형을 사용할 때 몇 가지 성능 차이가 있음을 알았습니다. 나는 모두가 a를 반환 할 것을 제안한다는 것을 알고있다 List<T>
또는 IEnumarable<T>
, DataGridView의 데이터 소스를 이에 설정하지만 불행히도 객체의 정렬을 지원하지는 않습니다. 주위에 약간의 파기 한 후 나는 그것을 발견했다 SortableBindingList<T>
~에 여기 MSDN. 나는 그것을 적용했고, 그리드는 스스로 채우는 데 1 초 미만이 걸렸다. 그러나 열을 클릭하여 정렬 할 때 정렬을 구현하는 데 1 초가 조금 걸렸다.
그런 다음 DataTable 경로로 가기로 결정했지만 유충 방법이 제거되었음을 알았지 만 더 많은 파기 후에는이를 구현할 수있는 방법을 찾았습니다. MSDN 기사. 그것을 적용한 후, 나는 검색이 그리드를 채우는 데 약 2 초가 걸렸다는 것을 발견했지만, 그 후 정렬 (19000 행에서)은 순간적이었습니다 !! 당연히 나는이 접근법을 고수했다.
또한 그리드 편집/추가/삭제를 비활성화했습니다. 그리드는 순전히 데이터를 표시하기위한 것입니다. 다른 CRUD 작업은 현재 선택된 행 (숨겨진 기본 키 열)에 따라 대화 상자 양식에 의해 제공됩니다.
두 가지 방법 모두에 사용한 코드는 다음과 같습니다.
1) SortableBindingList
//declare private member
private SortableBindingList<PdtAllocation> listAlloc = null;
private void RefreshData() {
bcsDataContext ctx = new bcsDataContext();
try {
listAlloc = new SortableBindingList<PdtAllocation>(ctx.PdtAllocation.ToList());
}
catch (Exception) {
throw;
}
finally {
ctx.Dispose();
}
dataGridView1.DataSource = listAlloc;
}
2) 복사 대상
//declare private member
private DataTable dt = null;
private void RefreshData() {
dt = new DataTable();
bcsDataContext ctx = new bcsDataContext();
try {
ctx.PdtAllocation.CopyToDataTable(dt, LoadOption.PreserveChanges);
}
catch (Exception) {
throw;
}
finally {
ctx.Dispose();
}
dataGridView1.DataSource = dt;
}
이제 나는 이것이 아마도 "묻고 대답했습니다"사례, 그러나 나는 당신의 의견뿐만 아니라 CopyToDataTable()
노선.
감사합니다 .... 그리고 루그 쿼리에 대해 사과드립니다!
해결책
여기에 당신의 질문에 대한 내 생각이 있습니다 ( SortableBindingList
노선).
일반적인 반사 기반 정렬 알고리즘을 사용 했습니까? 나는 처음에 이것을했고 성능은 정말 나빴다. 마지막으로 다음 솔루션을 생각해 냈습니다. 기본 정렬을 제공합니다. SortableBindingList<T>
또한 파생 클래스에서 특수 분류를 구현할 수있는 가능성을 열어 두십시오.
코드는 다음과 같습니다.
~ 안에 SortableBindingList<T>.ApplySortCore()
:
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
// Check if the sorted property implements IComparable
...
List<T> itemsList = (List<T>)this.Items;
Comparison<T> comparer = GetComparer(prop);
itemsList.Sort(comparer);
if (direction == ListSortDirection.Descending)
{
itemsList.Reverse();
}
...
// Set sort state (is sorted, sort property, sort dir)
}
일반 SortableBindingList<T>
기본 반사 기반 분류기를 제공합니다.
protected virtual Comparison<T> GetComparer(PropertyDescriptor prop)
{
return new Comparison<T>(delegate(T x, T y)
{
if (prop.GetValue(x) != null)
return ((IComparable)prop.GetValue(x)).CompareTo(prop.GetValue(y));
else if (prop.GetValue(y) != null)
return -1 * ((IComparable)prop.GetValue(y)).CompareTo(prop.GetValue(x));
else
return 0;
});
}
보시다시피 GetComparer()
가상이므로에서 파생 된 클래스에서 그것을 무시할 수 있습니다. SortableBindingList<T>
제공하기 위해 많이 더 빠른 비교, 실제로 정렬되는 속성의 유형에 따라 조정됩니다. 예를 들어, 일반 비교가 정렬되는 동안 ( String
속성) 100000 레코드 4 초 안에 전문 비교기는 70ms에서 동일한 작업을 수행했습니다.
class CustomerList : SortableBindingList<Customer>
{
protected override Comparison<Customer> GetComparer(PropertyDescriptor prop)
{
Comparison<Customer> comparer = null;
switch (prop.Name)
{
case "FirstName":
comparer = new Comparison<Customer>(delegate(Customer x, Customer y)
{
string xx = (null == x) ? null : x.FirstName;
string yy = (null == y) ? null : y.FirstName;
return String.Compare(xx, yy);
});
break;
...
}
return comparer;
}
}
마지막 참고 사항 : 게시 된 코드의 대부분은 SO 또는 Microsoft와 같은 다른 소스에서 복사/영감을 받았으므로 크레딧은 내 것이 아닙니다. 저의 유일한 기여는 비교기를 가상화하는 것이었지만 동일한 아이디어를 기반으로 약간의 인터넷 검색이 더 나은 솔루션을 더 잘 표현할 것이라고 확신합니다.