none
IEnumerale.Where()比DataTbale.Select()效率高的具体原因是什么? RRS feed

  • 问题

  • 对于IEnumerale.Where()比DataTbale.Select()效率高,尤其是在数据量较大的时候的效率对比结果是已知的。但是什么原因造成这样的结果?是否是CLR在代码第一次执行时需要对DataTbale.Select()的参数进行解析,而IEnumerale.Where()在编译时就已经推断出参数的Type,因此在生成IL时就已经对代码进行了优化造成的?

    有大师能对这两种方法的内部执行过程进行说明吗?最好能够说明效率差异在哪里。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Diagnostics;
    
    namespace LambdaDemo3
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("ID", typeof(string));
                Enumerable.Range(1, 10).ToList().ForEach(p => dt.Rows.Add(dt.NewRow()["ID"] = p.ToString()));
    
                dt.AsEnumerable().Where(p => Convert.ToInt32(p["ID"]) > 5);
                dt.Select("ID > 5");
            }
        }
    }
    


    Become a .net Nanja

    2014年2月16日 2:35

答案

  • Where:是一个Enumerable类的扩展方法,根据其方法来看肯定可以知道泛型中的那个实际类型:

    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } if (source is Enumerable.Iterator<TSource>) { return ((Enumerable.Iterator<TSource>)source).Where(predicate); } if (source is TSource[]) { return new Enumerable.WhereArrayIterator<TSource>((TSource[])source, predicate); } if (!(source is List<TSource>)) { return new Enumerable.WhereEnumerableIterator<TSource>(source, predicate); } return new Enumerable.WhereListIterator<TSource>((List<TSource>)source, predicate); }

    而Enumerable.WhereEnumerableIterator<TSource>:

     private class WhereEnumerableIterator<TSource> : Enumerable.Iterator<TSource>
            {
                private IEnumerable<TSource> source;
    
                private Func<TSource, bool> predicate;
    
                private IEnumerator<TSource> enumerator;
    
                [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
                public WhereEnumerableIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                    this.source = source;
                    this.predicate = predicate;
                }
    
                public override Enumerable.Iterator<TSource> Clone()
                {
                    return new Enumerable.WhereEnumerableIterator<TSource>(this.source, this.predicate);
                }
    
                public override void Dispose()
                {
                    if (this.enumerator != null)
                    {
                        this.enumerator.Dispose();
                    }
                    this.enumerator = null;
                    base.Dispose();
                }
    
                public override bool MoveNext()
                {
                    switch (this.state)
                    {
                        case 1:
                        {
                            this.enumerator = this.source.GetEnumerator();
                            this.state = 2;
                            goto case 2;
                        }
                        case 2:
                        {
                            while (this.enumerator.MoveNext())
                            {
                                TSource current = this.enumerator.Current;
                                if (!this.predicate(current))
                                {
                                    continue;
                                }
                                this.current = current;
                                return true;
                            }
                            this.Dispose();
                            break;
                        }
                    }
                    return false;
                }
    
                public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector)
                {
                    return new Enumerable.WhereSelectEnumerableIterator<TSource, TResult>(this.source, this.predicate, selector);
                }
    
                public override IEnumerable<TSource> Where(Func<TSource, bool> predicate)
                {
                    return new Enumerable.WhereEnumerableIterator<TSource>(this.source, Enumerable.CombinePredicates<TSource>(this.predicate, predicate));
                }
            }

    而Select方法:

    public DataRow[] Select(string filterExpression)
            {
                Bid.Trace("<ds.DataTable.Select|API> %d#, filterExpression='%ls'\n", this.ObjectID, filterExpression);
                return (new Select(this, filterExpression, "", DataViewRowState.CurrentRows)).SelectRows();
            }

    "Select"是一个内部类,完整代码:

     internal sealed class Select
        {
            private readonly DataTable table;
    
            private readonly IndexField[] IndexFields;
    
            private DataViewRowState recordStates;
    
            private DataExpression rowFilter;
    
            private ExpressionNode expression;
    
            private Index index;
    
            private int[] records;
    
            private int recordCount;
    
            private ExpressionNode linearExpression;
    
            private bool candidatesForBinarySearch;
    
            private Select.ColumnInfo[] candidateColumns;
    
            private int nCandidates;
    
            private int matchedCandidates;
    
            public Select(DataTable table, string filterExpression, string sort, DataViewRowState recordStates)
            {
                this.table = table;
                this.IndexFields = table.ParseSortString(sort);
                if (filterExpression != null && filterExpression.Length > 0)
                {
                    this.rowFilter = new DataExpression(this.table, filterExpression);
                    this.expression = this.rowFilter.ExpressionNode;
                }
                this.recordStates = recordStates;
            }
    
            private bool AcceptRecord(int record)
            {
                bool flag;
                DataRow item = this.table.recordManager[record];
                if (item == null)
                {
                    return true;
                }
                DataRowVersion dataRowVersion = DataRowVersion.Default;
                if (item.oldRecord == record)
                {
                    dataRowVersion = DataRowVersion.Original;
                }
                else if (item.newRecord == record)
                {
                    dataRowVersion = DataRowVersion.Current;
                }
                else if (item.tempRecord == record)
                {
                    dataRowVersion = DataRowVersion.Proposed;
                }
                object obj = this.linearExpression.Eval(item, dataRowVersion);
                try
                {
                    flag = DataExpression.ToBoolean(obj);
                }
                catch (Exception exception)
                {
                    if (ADP.IsCatchableExceptionType(exception))
                    {
                        throw ExprException.FilterConvertion(this.rowFilter.Expression);
                    }
                    throw;
                }
                return flag;
            }
    
            private void AnalyzeExpression(BinaryNode expr)
            {
                ExpressionNode binaryNode;
                if (this.linearExpression == this.expression)
                {
                    return;
                }
                if (expr.op == 27)
                {
                    this.linearExpression = this.expression;
                    return;
                }
                if (expr.op != 26)
                {
                    if (this.IsSupportedOperator(expr.op))
                    {
                        if (expr.left is NameNode && expr.right is ConstNode)
                        {
                            Select.ColumnInfo columnInfo = this.candidateColumns[((NameNode)expr.left).column.Ordinal];
                            columnInfo.expr = (columnInfo.expr == null ? expr : new BinaryNode(this.table, 26, expr, columnInfo.expr));
                            if (expr.op == 7)
                            {
                                columnInfo.equalsOperator = true;
                            }
                            this.candidatesForBinarySearch = true;
                            return;
                        }
                        if (expr.right is NameNode && expr.left is ConstNode)
                        {
                            ExpressionNode expressionNode = expr.left;
                            expr.left = expr.right;
                            expr.right = expressionNode;
                            switch (expr.op)
                            {
                                case 8:
                                {
                                    expr.op = 9;
                                    break;
                                }
                                case 9:
                                {
                                    expr.op = 8;
                                    break;
                                }
                                case 10:
                                {
                                    expr.op = 11;
                                    break;
                                }
                                case 11:
                                {
                                    expr.op = 10;
                                    break;
                                }
                            }
                            Select.ColumnInfo columnInfo1 = this.candidateColumns[((NameNode)expr.left).column.Ordinal];
                            columnInfo1.expr = (columnInfo1.expr == null ? expr : new BinaryNode(this.table, 26, expr, columnInfo1.expr));
                            if (expr.op == 7)
                            {
                                columnInfo1.equalsOperator = true;
                            }
                            this.candidatesForBinarySearch = true;
                            return;
                        }
                    }
                    this.linearExpression = (this.linearExpression == null ? expr : new BinaryNode(this.table, 26, expr, this.linearExpression));
                    return;
                }
                bool flag = false;
                bool flag1 = false;
                if (!(expr.left is BinaryNode))
                {
                    UnaryNode unaryNode = expr.left as UnaryNode;
                    if (unaryNode != null)
                    {
                        while (unaryNode.op == 0 && unaryNode.right is UnaryNode && ((UnaryNode)unaryNode.right).op == 0)
                        {
                            unaryNode = (UnaryNode)unaryNode.right;
                        }
                        if (unaryNode.op == 0 && unaryNode.right is BinaryNode)
                        {
                            this.AnalyzeExpression((BinaryNode)unaryNode.right);
                            if (this.linearExpression == this.expression)
                            {
                                return;
                            }
                            flag = true;
                        }
                    }
                }
                else
                {
                    this.AnalyzeExpression((BinaryNode)expr.left);
                    if (this.linearExpression == this.expression)
                    {
                        return;
                    }
                    flag = true;
                }
                if (!(expr.right is BinaryNode))
                {
                    UnaryNode unaryNode1 = expr.right as UnaryNode;
                    if (unaryNode1 != null)
                    {
                        while (unaryNode1.op == 0 && unaryNode1.right is UnaryNode && ((UnaryNode)unaryNode1.right).op == 0)
                        {
                            unaryNode1 = (UnaryNode)unaryNode1.right;
                        }
                        if (unaryNode1.op == 0 && unaryNode1.right is BinaryNode)
                        {
                            this.AnalyzeExpression((BinaryNode)unaryNode1.right);
                            if (this.linearExpression == this.expression)
                            {
                                return;
                            }
                            flag1 = true;
                        }
                    }
                }
                else
                {
                    this.AnalyzeExpression((BinaryNode)expr.right);
                    if (this.linearExpression == this.expression)
                    {
                        return;
                    }
                    flag1 = true;
                }
                if (flag && flag1)
                {
                    return;
                }
                ExpressionNode expressionNode1 = (flag ? expr.right : expr.left);
                if (this.linearExpression == null)
                {
                    binaryNode = expressionNode1;
                }
                else
                {
                    binaryNode = new BinaryNode(this.table, 26, expressionNode1, this.linearExpression);
                }
                this.linearExpression = binaryNode;
            }
    
            private void BuildLinearExpression()
            {
                int i;
                IndexField[] indexFields = this.index.IndexFields;
                for (i = 0; i < this.matchedCandidates; i++)
                {
                    Select.ColumnInfo columnInfo = this.candidateColumns[indexFields[i].Column.Ordinal];
                    columnInfo.flag = true;
                }
                int length = (int)this.candidateColumns.Length;
                for (i = 0; i < length; i++)
                {
                    if (this.candidateColumns[i] != null)
                    {
                        if (this.candidateColumns[i].flag)
                        {
                            this.candidateColumns[i].flag = false;
                        }
                        else if (this.candidateColumns[i].expr != null)
                        {
                            this.linearExpression = (this.linearExpression == null ? this.candidateColumns[i].expr : new BinaryNode(this.table, 26, this.candidateColumns[i].expr, this.linearExpression));
                        }
                    }
                }
            }
    
            private int CompareClosestCandidateIndexDesc(IndexField[] fields)
            {
                int i;
                int num = ((int)fields.Length < this.nCandidates ? (int)fields.Length : this.nCandidates);
                for (i = 0; i < num; i++)
                {
                    Select.ColumnInfo columnInfo = this.candidateColumns[fields[i].Column.Ordinal];
                    if (columnInfo == null || columnInfo.expr == null)
                    {
                        break;
                    }
                    if (!columnInfo.equalsOperator)
                    {
                        return i + 1;
                    }
                }
                return i;
            }
    
            private int CompareRecords(int record1, int record2)
            {
                int num;
                int num1;
                int length = (int)this.IndexFields.Length;
                for (int i = 0; i < length; i++)
                {
                    int num2 = this.IndexFields[i].Column.Compare(record1, record2);
                    if (num2 != 0)
                    {
                        if (this.IndexFields[i].IsDescending)
                        {
                            num2 = -num2;
                        }
                        return num2;
                    }
                }
                long recordState = (this.table.recordManager[record1] == null ? (long)0 : this.table.recordManager[record1].rowID);
                long recordState1 = (this.table.recordManager[record2] == null ? (long)0 : this.table.recordManager[record2].rowID);
                if (recordState < recordState1)
                {
                    num = -1;
                }
                else
                {
                    num = (recordState1 < recordState ? 1 : 0);
                }
                int num3 = num;
                if (num3 == 0 && record1 != record2 && this.table.recordManager[record1] != null && this.table.recordManager[record2] != null)
                {
                    recordState = (long)this.table.recordManager[record1].GetRecordState(record1);
                    recordState1 = (long)this.table.recordManager[record2].GetRecordState(record2);
                    if (recordState < recordState1)
                    {
                        num1 = -1;
                    }
                    else
                    {
                        num1 = (recordState1 < recordState ? 1 : 0);
                    }
                    num3 = num1;
                }
                return num3;
            }
    
            private bool CompareSortIndexDesc(IndexField[] fields)
            {
                if ((int)fields.Length < (int)this.IndexFields.Length)
                {
                    return false;
                }
                int num = 0;
                for (int i = 0; i < (int)fields.Length && num < (int)this.IndexFields.Length; i++)
                {
                    if (fields[i] != this.IndexFields[num])
                    {
                        Select.ColumnInfo columnInfo = this.candidateColumns[fields[i].Column.Ordinal];
                        if (columnInfo == null || !columnInfo.equalsOperator)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        num++;
                    }
                }
                return num == (int)this.IndexFields.Length;
            }
    
            private void CreateIndex()
            {
                Select.ColumnInfo columnInfo;
                if (this.index == null)
                {
                    if (this.nCandidates == 0)
                    {
                        this.index = new Index(this.table, this.IndexFields, this.recordStates, null);
                        this.index.AddRef();
                        return;
                    }
                    int length = (int)this.candidateColumns.Length;
                    int num = (int)this.IndexFields.Length;
                    bool flag = true;
                    int i = 0;
                    while (i < length)
                    {
                        if (this.candidateColumns[i] == null || this.candidateColumns[i].equalsOperator)
                        {
                            i++;
                        }
                        else
                        {
                            flag = false;
                            break;
                        }
                    }
                    int num1 = 0;
                    for (i = 0; i < num; i++)
                    {
                        Select.ColumnInfo columnInfo1 = this.candidateColumns[this.IndexFields[i].Column.Ordinal];
                        if (columnInfo1 != null)
                        {
                            columnInfo1.flag = true;
                            num1++;
                        }
                    }
                    IndexField[] indexField = new IndexField[this.nCandidates + (num - num1)];
                    if (flag)
                    {
                        num1 = 0;
                        for (i = 0; i < length; i++)
                        {
                            if (this.candidateColumns[i] != null)
                            {
                                int num2 = num1;
                                num1 = num2 + 1;
                                indexField[num2] = new IndexField(this.table.Columns[i], false);
                                this.candidateColumns[i].flag = false;
                            }
                        }
                        for (i = 0; i < num; i++)
                        {
                            Select.ColumnInfo columnInfo2 = this.candidateColumns[this.IndexFields[i].Column.Ordinal];
                            if (columnInfo2 == null || columnInfo2.flag)
                            {
                                int num3 = num1;
                                num1 = num3 + 1;
                                indexField[num3] = this.IndexFields[i];
                                if (columnInfo2 != null)
                                {
                                    columnInfo2.flag = false;
                                }
                            }
                        }
                        for (i = 0; i < (int)this.candidateColumns.Length; i++)
                        {
                            if (this.candidateColumns[i] != null)
                            {
                                this.candidateColumns[i].flag = false;
                            }
                        }
                        this.index = new Index(this.table, indexField, this.recordStates, null);
                        if (!this.IsOperatorIn(this.expression))
                        {
                            this.index.AddRef();
                        }
                        this.matchedCandidates = this.nCandidates;
                        return;
                    }
                    for (i = 0; i < num; i++)
                    {
                        indexField[i] = this.IndexFields[i];
                        Select.ColumnInfo columnInfo3 = this.candidateColumns[this.IndexFields[i].Column.Ordinal];
                        if (columnInfo3 != null)
                        {
                            columnInfo3.flag = true;
                        }
                    }
                    num1 = i;
                    for (i = 0; i < length; i++)
                    {
                        if (this.candidateColumns[i] != null)
                        {
                            if (this.candidateColumns[i].flag)
                            {
                                this.candidateColumns[i].flag = false;
                            }
                            else
                            {
                                int num4 = num1;
                                num1 = num4 + 1;
                                indexField[num4] = new IndexField(this.table.Columns[i], false);
                            }
                        }
                    }
                    this.index = new Index(this.table, indexField, this.recordStates, null);
                    this.matchedCandidates = 0;
                    if (this.linearExpression != this.expression)
                    {
                        IndexField[] indexFields = this.index.IndexFields;
                        do
                        {
                            if (this.matchedCandidates >= num1)
                            {
                                break;
                            }
                            columnInfo = this.candidateColumns[indexFields[this.matchedCandidates].Column.Ordinal];
                            if (columnInfo == null || columnInfo.expr == null)
                            {
                                break;
                            }
                            Select select = this;
                            select.matchedCandidates = select.matchedCandidates + 1;
                        }
                        while (columnInfo.equalsOperator);
                    }
                    for (i = 0; i < (int)this.candidateColumns.Length; i++)
                    {
                        if (this.candidateColumns[i] != null)
                        {
                            this.candidateColumns[i].flag = false;
                        }
                    }
                }
            }
    
            private int Eval(BinaryNode expr, DataRow row, DataRowVersion version)
            {
                object obj;
                StorageType storageType;
                object obj1;
                object obj2;
                object obj3;
                object obj4;
                object obj5;
                object obj6;
                object obj7;
                CompareInfo compareInfo;
                if (expr.op == 26)
                {
                    int num = this.Eval((BinaryNode)expr.left, row, version);
                    if (num != 0)
                    {
                        return num;
                    }
                    int num1 = this.Eval((BinaryNode)expr.right, row, version);
                    if (num1 != 0)
                    {
                        return num1;
                    }
                    return 0;
                }
                long num2 = (long)0;
                object obj8 = expr.left.Eval(row, version);
                if (expr.op != 13 && expr.op != 39)
                {
                    obj = expr.right.Eval(row, version);
                    bool flag = expr.left is ConstNode;
                    bool flag1 = expr.right is ConstNode;
                    if (obj8 == DBNull.Value || expr.left.IsSqlColumn && DataStorage.IsObjectSqlNull(obj8))
                    {
                        return -1;
                    }
                    if (obj == DBNull.Value || expr.right.IsSqlColumn && DataStorage.IsObjectSqlNull(obj))
                    {
                        return 1;
                    }
                    StorageType storageType1 = DataStorage.GetStorageType(obj8.GetType());
                    if (StorageType.Char == storageType1)
                    {
                        obj = (flag1 || !expr.right.IsSqlColumn ? Convert.ToChar(obj, this.table.FormatProvider) : SqlConvert.ChangeType2(obj, StorageType.Char, typeof(char), this.table.FormatProvider));
                    }
                    StorageType storageType2 = DataStorage.GetStorageType(obj.GetType());
                    storageType = (expr.left.IsSqlColumn || expr.right.IsSqlColumn ? expr.ResultSqlType(storageType1, storageType2, flag, flag1, expr.op) : expr.ResultType(storageType1, storageType2, flag, flag1, expr.op));
                    if (storageType == StorageType.Empty)
                    {
                        expr.SetTypeMismatchError(expr.op, obj8.GetType(), obj.GetType());
                    }
                    NameNode nameNode = null;
                    if (flag && !flag1 && storageType1 == StorageType.String && storageType2 == StorageType.Guid)
                    {
                        NameNode nameNode1 = expr.right as NameNode;
                        nameNode = nameNode1;
                        if (nameNode1 != null && nameNode.column.DataType == typeof(Guid))
                        {
                            goto Label0;
                        }
                    }
                    if (flag1 && !flag && storageType2 == StorageType.String && storageType1 == StorageType.Guid)
                    {
                        NameNode nameNode2 = expr.left as NameNode;
                        nameNode = nameNode2;
                        if (nameNode2 != null && nameNode.column.DataType == typeof(Guid))
                        {
                            goto Label0;
                        }
                    }
                    compareInfo = null;
                    goto Label1;
                }
            Label3:
                int num3 = expr.op;
                switch (num3)
                {
                    case 7:
                    {
                        if (num2 == (long)0)
                        {
                            obj1 = null;
                        }
                        else
                        {
                            obj1 = (num2 < (long)0 ? -1 : 1);
                        }
                        num2 = (long)obj1;
                        return (int)num2;
                    }
                    case 8:
                    {
                        if (num2 > (long)0)
                        {
                            obj2 = null;
                        }
                        else
                        {
                            obj2 = -1;
                        }
                        num2 = (long)obj2;
                        return (int)num2;
                    }
                    case 9:
                    {
                        if (num2 < (long)0)
                        {
                            obj3 = null;
                        }
                        else
                        {
                            obj3 = 1;
                        }
                        num2 = (long)obj3;
                        return (int)num2;
                    }
                    case 10:
                    {
                        if (num2 >= (long)0)
                        {
                            obj4 = null;
                        }
                        else
                        {
                            obj4 = -1;
                        }
                        num2 = (long)obj4;
                        return (int)num2;
                    }
                    case 11:
                    {
                        if (num2 <= (long)0)
                        {
                            obj5 = null;
                        }
                        else
                        {
                            obj5 = 1;
                        }
                        num2 = (long)obj5;
                        return (int)num2;
                    }
                    case 12:
                    {
                        return (int)num2;
                    }
                    case 13:
                    {
                        if (obj8 == DBNull.Value)
                        {
                            obj6 = null;
                        }
                        else
                        {
                            obj6 = -1;
                        }
                        num2 = (long)obj6;
                        return (int)num2;
                    }
                    default:
                    {
                        if (num3 == 39)
                        {
                            if (obj8 != DBNull.Value)
                            {
                                obj7 = null;
                            }
                            else
                            {
                                obj7 = 1;
                            }
                            num2 = (long)obj7;
                            return (int)num2;
                        }
                        else
                        {
                            return (int)num2;
                        }
                    }
                }
            Label0:
                compareInfo = CultureInfo.InvariantCulture.CompareInfo;
            Label1:
                CompareInfo compareInfo1 = compareInfo;
                num2 = (long)expr.BinaryCompare(obj8, obj, storageType, expr.op, compareInfo1);
                goto Label3;
            }
    
            private int Evaluate(int record)
            {
                DataRow item = this.table.recordManager[record];
                if (item == null)
                {
                    return 0;
                }
                DataRowVersion dataRowVersion = DataRowVersion.Default;
                if (item.oldRecord == record)
                {
                    dataRowVersion = DataRowVersion.Original;
                }
                else if (item.newRecord == record)
                {
                    dataRowVersion = DataRowVersion.Current;
                }
                else if (item.tempRecord == record)
                {
                    dataRowVersion = DataRowVersion.Proposed;
                }
                IndexField[] indexFields = this.index.IndexFields;
                for (int i = 0; i < this.matchedCandidates; i++)
                {
                    int ordinal = indexFields[i].Column.Ordinal;
                    int num = this.Eval(this.candidateColumns[ordinal].expr, item, dataRowVersion);
                    if (num != 0)
                    {
                        if (!indexFields[i].IsDescending)
                        {
                            return num;
                        }
                        return -num;
                    }
                }
                return 0;
            }
    
            private bool FindClosestCandidateIndex()
            {
                bool flag;
                this.index = null;
                this.matchedCandidates = 0;
                bool flag1 = true;
                this.table.indexesLock.AcquireReaderLock(-1);
                try
                {
                    int count = this.table.indexes.Count;
                    int num = this.table.Rows.Count;
                    for (int i = 0; i < count; i++)
                    {
                        Index item = this.table.indexes[i];
                        if (item.RecordStates == this.recordStates && item.IsSharable)
                        {
                            int num1 = this.CompareClosestCandidateIndexDesc(item.IndexFields);
                            if (num1 > this.matchedCandidates || num1 == this.matchedCandidates && !flag1)
                            {
                                this.matchedCandidates = num1;
                                this.index = item;
                                flag1 = this.CompareSortIndexDesc(item.IndexFields);
                                if (this.matchedCandidates == this.nCandidates && flag1)
                                {
                                    flag = true;
                                    return flag;
                                }
                            }
                        }
                    }
                    if (this.index == null)
                    {
                        return false;
                    }
                    return flag1;
                }
                finally
                {
                    this.table.indexesLock.ReleaseReaderLock();
                }
                return flag;
            }
    
            private int FindFirstMatchingRecord()
            {
                int num = -1;
                int num1 = 0;
                int recordCount = this.index.RecordCount - 1;
                while (num1 <= recordCount)
                {
                    int num2 = num1 + recordCount >> 1;
                    int num3 = this.Evaluate(this.index.GetRecord(num2));
                    if (num3 == 0)
                    {
                        num = num2;
                    }
                    if (num3 >= 0)
                    {
                        recordCount = num2 - 1;
                    }
                    else
                    {
                        num1 = num2 + 1;
                    }
                }
                return num;
            }
    
            private int FindLastMatchingRecord(int lo)
            {
                int num = -1;
                int recordCount = this.index.RecordCount - 1;
                while (lo <= recordCount)
                {
                    int num1 = lo + recordCount >> 1;
                    int num2 = this.Evaluate(this.index.GetRecord(num1));
                    if (num2 == 0)
                    {
                        num = num1;
                    }
                    if (num2 > 0)
                    {
                        recordCount = num1 - 1;
                    }
                    else
                    {
                        lo = num1 + 1;
                    }
                }
                return num;
            }
    
            private bool FindSortIndex()
            {
                bool flag;
                this.index = null;
                this.table.indexesLock.AcquireReaderLock(-1);
                try
                {
                    int count = this.table.indexes.Count;
                    int num = this.table.Rows.Count;
                    int num1 = 0;
                    while (num1 < count)
                    {
                        Index item = this.table.indexes[num1];
                        if (item.RecordStates != this.recordStates || !item.IsSharable || !this.CompareSortIndexDesc(item.IndexFields))
                        {
                            num1++;
                        }
                        else
                        {
                            this.index = item;
                            flag = true;
                            return flag;
                        }
                    }
                    return false;
                }
                finally
                {
                    this.table.indexesLock.ReleaseReaderLock();
                }
                return flag;
            }
    
            private Range GetBinaryFilteredRecords()
            {
                if (this.matchedCandidates == 0)
                {
                    return new Range(0, this.index.RecordCount - 1);
                }
                int num = this.FindFirstMatchingRecord();
                if (num == -1)
                {
                    return new Range();
                }
                return new Range(num, this.FindLastMatchingRecord(num));
            }
    
            private int[] GetLinearFilteredRecords(Range range)
            {
                if (this.linearExpression == null)
                {
                    int[] current = new int[range.Count];
                    RBTree<int>.RBTreeEnumerator enumerator = this.index.GetEnumerator(range.Min);
                    for (int i = 0; i < range.Count && enumerator.MoveNext(); i++)
                    {
                        current[i] = enumerator.Current;
                    }
                    return current;
                }
                List<int> nums = new List<int>();
                RBTree<int>.RBTreeEnumerator rBTreeEnumerator = this.index.GetEnumerator(range.Min);
                for (int j = 0; j < range.Count && rBTreeEnumerator.MoveNext(); j++)
                {
                    if (this.AcceptRecord(rBTreeEnumerator.Current))
                    {
                        nums.Add(rBTreeEnumerator.Current);
                    }
                }
                return nums.ToArray();
            }
    
            private DataRow[] GetLinearFilteredRows(Range range)
            {
                if (this.linearExpression == null)
                {
                    return this.index.GetRows(range);
                }
                List<DataRow> dataRows = new List<DataRow>();
                RBTree<int>.RBTreeEnumerator enumerator = this.index.GetEnumerator(range.Min);
                for (int i = 0; i < range.Count && enumerator.MoveNext(); i++)
                {
                    if (this.AcceptRecord(enumerator.Current))
                    {
                        dataRows.Add(this.table.recordManager[enumerator.Current]);
                    }
                }
                DataRow[] dataRowArray = this.table.NewRowArray(dataRows.Count);
                dataRows.CopyTo(dataRowArray);
                return dataRowArray;
            }
    
            public DataRow[] GetRows()
            {
                DataRow[] item = this.table.NewRowArray(this.recordCount);
                for (int i = 0; i < (int)item.Length; i++)
                {
                    item[i] = this.table.recordManager[this.records[i]];
                }
                return item;
            }
    
            private void InitCandidateColumns()
            {
                this.nCandidates = 0;
                this.candidateColumns = new Select.ColumnInfo[this.table.Columns.Count];
                if (this.rowFilter == null)
                {
                    return;
                }
                DataColumn[] dependency = this.rowFilter.GetDependency();
                for (int i = 0; i < (int)dependency.Length; i++)
                {
                    if (dependency[i].Table == this.table)
                    {
                        this.candidateColumns[dependency[i].Ordinal] = new Select.ColumnInfo();
                        Select select = this;
                        select.nCandidates = select.nCandidates + 1;
                    }
                }
            }
    
            private bool IsOperatorIn(ExpressionNode enode)
            {
                BinaryNode binaryNode = enode as BinaryNode;
                if (binaryNode != null && (5 == binaryNode.op || this.IsOperatorIn(binaryNode.right) || this.IsOperatorIn(binaryNode.left)))
                {
                    return true;
                }
                return false;
            }
    
            private bool IsSupportedOperator(int op)
            {
                if (op >= 7 && op <= 11 || op == 13)
                {
                    return true;
                }
                return op == 39;
            }
    
            public DataRow[] SelectRows()
            {
                Range range;
                bool flag = true;
                this.InitCandidateColumns();
                if (!(this.expression is BinaryNode))
                {
                    this.linearExpression = this.expression;
                }
                else
                {
                    this.AnalyzeExpression((BinaryNode)this.expression);
                    if (!this.candidatesForBinarySearch)
                    {
                        this.linearExpression = this.expression;
                    }
                    if (this.linearExpression != this.expression)
                    {
                        flag = !this.FindClosestCandidateIndex();
                    }
                    else
                    {
                        for (int i = 0; i < (int)this.candidateColumns.Length; i++)
                        {
                            if (this.candidateColumns[i] != null)
                            {
                                this.candidateColumns[i].equalsOperator = false;
                                this.candidateColumns[i].expr = null;
                            }
                        }
                    }
                }
                if (this.index == null && ((int)this.IndexFields.Length > 0 || this.linearExpression == this.expression))
                {
                    flag = !this.FindSortIndex();
                }
                if (this.index == null)
                {
                    this.CreateIndex();
                    flag = false;
                }
                if (this.index.RecordCount == 0)
                {
                    return this.table.NewRowArray(0);
                }
                if (this.matchedCandidates == 0)
                {
                    range = new Range(0, this.index.RecordCount - 1);
                    this.linearExpression = this.expression;
                    return this.GetLinearFilteredRows(range);
                }
                range = this.GetBinaryFilteredRecords();
                if (range.Count == 0)
                {
                    return this.table.NewRowArray(0);
                }
                if (this.matchedCandidates < this.nCandidates)
                {
                    this.BuildLinearExpression();
                }
                if (!flag)
                {
                    return this.GetLinearFilteredRows(range);
                }
                this.records = this.GetLinearFilteredRecords(range);
                this.recordCount = (int)this.records.Length;
                if (this.recordCount == 0)
                {
                    return this.table.NewRowArray(0);
                }
                this.Sort(0, this.recordCount - 1);
                return this.GetRows();
            }
    
            private void Sort(int left, int right)
            {
                int num;
                do
                {
                    num = left;
                    int num1 = right;
                    int num2 = this.records[num + num1 >> 1];
                    do
                    {
                    Label0:
                        if (this.CompareRecords(this.records[num], num2) < 0)
                        {
                            num++;
                            goto Label0;
                        }
                        else
                        {
                            while (this.CompareRecords(this.records[num1], num2) > 0)
                            {
                                num1--;
                            }
                            if (num > num1)
                            {
                                continue;
                            }
                            int num3 = this.records[num];
                            this.records[num] = this.records[num1];
                            this.records[num1] = num3;
                            num++;
                            num1--;
                        }
                    }
                    while (num <= num1);
                    if (left < num1)
                    {
                        this.Sort(left, num1);
                    }
                    left = num;
                }
                while (num < right);
            }
    
            private sealed class ColumnInfo
            {
                public bool flag;
    
                public bool equalsOperator;
    
                public BinaryNode expr;
    
                public ColumnInfo()
                {
                }
            }
        }

    结论:Select先根据字符串构造二叉树(计算表达式),然后计算;而Where直接计算了(委托)。


    ASP.NET Forum
    Other Discussion Forums
    FreeRice Donate
    Issues to report
    Free Tech Books Search and Download

    2014年2月16日 3:14
    版主