Skip to content

Commit e07f2c7

Browse files
committed
Get rid of as many SqlColumnCollection related allocations as possible
1 parent 120afaf commit e07f2c7

File tree

12 files changed

+165
-119
lines changed

12 files changed

+165
-119
lines changed

Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ internal sealed partial class ExpressionProcessor : ExpressionVisitor<SqlExpress
2828
private readonly StorageDriver driver;
2929
private readonly BooleanExpressionConverter booleanExpressionConverter;
3030
private readonly IMemberCompilerProvider<SqlExpression> memberCompilerProvider;
31-
private readonly List<SqlExpression>[] sourceColumns;
31+
private readonly IReadOnlyList<SqlExpression>[] sourceColumns;
3232
private readonly ExpressionEvaluator evaluator;
3333
private readonly ParameterExtractor parameterExtractor;
3434
private readonly LambdaExpression lambda;
3535
private readonly HashSet<QueryParameterBinding> bindings;
3636
private readonly List<ParameterExpression> activeParameters;
37-
private readonly Dictionary<ParameterExpression, List<SqlExpression>> sourceMapping;
37+
private readonly Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>> sourceMapping;
3838
private readonly SqlCompiler compiler;
3939

4040
private readonly Dictionary<QueryParameterIdentity, QueryParameterBinding> bindingsWithIdentity
@@ -448,7 +448,7 @@ private SqlExpression TryUnwrapEnum(SqlContainer container)
448448
// Constructors
449449

450450
public ExpressionProcessor(
451-
LambdaExpression lambda, HandlerAccessor handlers, SqlCompiler compiler, params List<SqlExpression>[] sourceColumns)
451+
LambdaExpression lambda, HandlerAccessor handlers, SqlCompiler compiler, params IReadOnlyList<SqlExpression>[] sourceColumns)
452452
{
453453
ArgumentValidator.EnsureArgumentNotNull(lambda, "lambda");
454454
ArgumentValidator.EnsureArgumentNotNull(handlers, "handlers");
@@ -478,7 +478,7 @@ public ExpressionProcessor(
478478
throw Exceptions.InternalError(Strings.ExParametersCountIsNotSameAsSourceColumnListsCount, OrmLog.Instance);
479479
if (sourceColumns.Any(list => list.Any(c => c.IsNullReference())))
480480
throw Exceptions.InternalError(Strings.ExSourceColumnListContainsNullValues, OrmLog.Instance);
481-
sourceMapping = new Dictionary<ParameterExpression, List<SqlExpression>>();
481+
sourceMapping = new Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>>();
482482
}
483483
}
484484
}

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Apply.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,15 @@ private SqlSelect ProcessApplyViaCrossApply(ApplyProvider provider, SqlProvider
167167
? left.PermanentReference
168168
: left.Request.Statement.From;
169169
var leftColumns = leftShouldUseReference
170-
? leftTable.Columns.Cast<SqlColumn>()
170+
? (IReadOnlyList<SqlColumn>) leftTable.Columns
171171
: left.Request.Statement.Columns;
172172

173173
var rightShouldUseReference = ShouldUseQueryReference(provider, right);
174174
var rightTable = rightShouldUseReference
175175
? right.PermanentReference
176176
: right.Request.Statement.From;
177177
var rightColumns = rightShouldUseReference
178-
? rightTable.Columns.Cast<SqlColumn>()
178+
? (IReadOnlyList<SqlColumn>) rightTable.Columns
179179
: right.Request.Statement.Columns;
180180

181181
var joinType = provider.ApplyType==JoinType.LeftOuter
@@ -186,8 +186,8 @@ private SqlSelect ProcessApplyViaCrossApply(ApplyProvider provider, SqlProvider
186186
joinType,
187187
leftTable,
188188
rightTable,
189-
leftColumns.ToList(),
190-
rightColumns.ToList());
189+
leftColumns,
190+
rightColumns);
191191

192192
var query = SqlDml.Select(joinedTable);
193193
if (!leftShouldUseReference)

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ protected virtual string ProcessAliasedName(string name)
6767
}
6868

6969
protected Pair<SqlExpression, IEnumerable<QueryParameterBinding>> ProcessExpression(LambdaExpression le,
70-
params List<SqlExpression>[] sourceColumns)
70+
params IReadOnlyList<SqlExpression>[] sourceColumns)
7171
{
7272
var processor = new ExpressionProcessor(le, Handlers, this, sourceColumns);
7373
var result = new Pair<SqlExpression, IEnumerable<QueryParameterBinding>>(

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ protected override SqlProvider VisitJoin(JoinProvider provider)
175175
? left.PermanentReference
176176
: left.Request.Statement.From;
177177
var leftColumns = leftShouldUseReference
178-
? leftTable.Columns.Cast<SqlColumn>()
178+
? (IReadOnlyList<SqlColumn>) leftTable.Columns
179179
: left.Request.Statement.Columns;
180180
var leftExpressions = leftShouldUseReference
181181
? leftTable.Columns.Cast<SqlExpression>().ToList()
@@ -186,7 +186,7 @@ protected override SqlProvider VisitJoin(JoinProvider provider)
186186
? right.PermanentReference
187187
: right.Request.Statement.From;
188188
var rightColumns = rightShouldUseReference
189-
? rightTable.Columns.Cast<SqlColumn>()
189+
? (IReadOnlyList<SqlColumn>) rightTable.Columns
190190
: right.Request.Statement.Columns;
191191
var rightExpressions = rightShouldUseReference
192192
? rightTable.Columns.Cast<SqlExpression>().ToList()
@@ -207,8 +207,8 @@ protected override SqlProvider VisitJoin(JoinProvider provider)
207207
joinType,
208208
leftTable,
209209
rightTable,
210-
leftColumns.ToList(),
211-
rightColumns.ToList(),
210+
leftColumns,
211+
rightColumns,
212212
joinExpression);
213213

214214
var query = SqlDml.Select(joinedTable);
@@ -231,21 +231,21 @@ protected override SqlProvider VisitPredicateJoin(PredicateJoinProvider provider
231231
? left.PermanentReference
232232
: left.Request.Statement.From;
233233
var leftColumns = leftShouldUseReference
234-
? leftTable.Columns.Cast<SqlColumn>()
234+
? (IReadOnlyList<SqlColumn>) leftTable.Columns
235235
: left.Request.Statement.Columns;
236236
var leftExpressions = leftShouldUseReference
237-
? leftTable.Columns.Cast<SqlExpression>().ToList()
237+
? (IReadOnlyList<SqlExpression>) leftTable.Columns
238238
: ExtractColumnExpressions(left.Request.Statement);
239239

240240
var rightShouldUseReference = ShouldUseQueryReference(provider, right);
241241
var rightTable = rightShouldUseReference
242242
? right.PermanentReference
243243
: right.Request.Statement.From;
244244
var rightColumns = rightShouldUseReference
245-
? rightTable.Columns.Cast<SqlColumn>()
245+
? (IReadOnlyList<SqlColumn>) rightTable.Columns
246246
: right.Request.Statement.Columns;
247247
var rightExpressions = rightShouldUseReference
248-
? rightTable.Columns.Cast<SqlExpression>().ToList()
248+
? (IReadOnlyList<SqlExpression>) rightTable.Columns
249249
: ExtractColumnExpressions(right.Request.Statement);
250250

251251

@@ -259,8 +259,8 @@ protected override SqlProvider VisitPredicateJoin(PredicateJoinProvider provider
259259
joinType,
260260
leftTable,
261261
rightTable,
262-
leftColumns.ToList(),
263-
rightColumns.ToList(),
262+
leftColumns,
263+
rightColumns,
264264
joinExpression);
265265

266266
var query = SqlDml.Select(joinedTable);

Orm/Xtensive.Orm/Sql/Dml/Collections/SqlColumnCollection.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ public class SqlColumnCollection : ICollection<SqlColumn>, IReadOnlyList<SqlColu
3939
public List<SqlColumn>.Enumerator GetEnumerator() => columnList.GetEnumerator();
4040

4141
/// <summary>
42-
/// Gets the column at the specified <paramref name="index"/>.
42+
/// Gets or sets the column at the specified <paramref name="index"/>.
4343
/// </summary>
44-
public SqlColumn this[int index] => columnList[index];
44+
public SqlColumn this[int index]
45+
{
46+
get => columnList[index];
47+
set => columnList[index] = value;
48+
}
4549

4650
/// <summary>
4751
/// Gets the column with the specified <paramref name="name"/>
@@ -141,9 +145,18 @@ public SqlColumnCollection()
141145
/// <summary>
142146
/// Initializes new instance of this type.
143147
/// </summary>
144-
public SqlColumnCollection(IReadOnlyList<SqlColumn> list)
148+
public SqlColumnCollection(IEnumerable<SqlColumn> columns)
149+
{
150+
columnList = new List<SqlColumn>(columns);
151+
}
152+
153+
/// <summary>
154+
/// Initializes a new instance of the <see cref="SqlColumnCollection"/> class.
155+
/// This is special version it uses provided list as is.
156+
/// </summary>
157+
internal SqlColumnCollection(List<SqlColumn> columns)
145158
{
146-
columnList = new List<SqlColumn>(list);
159+
columnList = columns;
147160
}
148161
}
149162
}

Orm/Xtensive.Orm/Sql/Dml/Collections/SqlTableColumnCollection.cs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class SqlTableColumnCollection : IReadOnlyList<SqlTableColumn>
1616
{
1717
private static readonly StringComparer Comparer = StringComparer.OrdinalIgnoreCase;
1818
private readonly List<SqlTableColumn> columnList;
19-
private readonly Dictionary<string, SqlTableColumn> columnLookup;
19+
private Dictionary<string, SqlTableColumn> columnLookup;
2020

2121
/// <summary>
2222
/// Gets the number of elements contained in the <see cref="SqlTableColumnCollection"/>.
@@ -50,33 +50,52 @@ public SqlTableColumn this[string name]
5050
return null;
5151
}
5252

53-
if (columnLookup == null) {
54-
return columnList.Find(column => Comparer.Equals(column.Name, name));
53+
if (columnLookup != null) {
54+
return columnLookup.TryGetValue(name, out var column) ? column : null;
5555
}
5656

57-
{
58-
return columnLookup.TryGetValue(name, out var column) ? column : null;
57+
var count = columnList.Count;
58+
if (count <= 16) {
59+
foreach (var column in columnList) {
60+
if (Comparer.Equals(column.Name, name)) {
61+
return column;
62+
}
63+
}
64+
65+
return null;
5966
}
67+
68+
SqlTableColumn result = null;
69+
columnLookup = new Dictionary<string, SqlTableColumn>(count, Comparer);
70+
for (var index = count - 1; index >= 0; index--) {
71+
var column = columnList[index];
72+
var columnName = column.Name;
73+
columnLookup[columnName] = column;
74+
if (Comparer.Equals(columnName, name)) {
75+
result = column;
76+
}
77+
}
78+
79+
return result;
6080
}
6181
}
6282

6383
/// <summary>
6484
/// Initializes a new instance of the <see cref="SqlTableColumnCollection"/> class.
6585
/// </summary>
6686
/// <param name="columns">A collection of <see cref="SqlTableColumn"/>s to be wrapped.</param>
67-
public SqlTableColumnCollection(IReadOnlyCollection<SqlTableColumn> columns)
87+
public SqlTableColumnCollection(IEnumerable<SqlTableColumn> columns)
6888
{
69-
if (columns.Count <= 8) {
70-
columnList = new List<SqlTableColumn>(columns);
71-
}
72-
else {
73-
columnList = new List<SqlTableColumn>(columns.Count);
74-
columnLookup = new Dictionary<string, SqlTableColumn>(columns.Count, Comparer);
75-
foreach (var column in columns) {
76-
columnList.Add(column);
77-
columnLookup.Add(column.Name, column);
78-
}
79-
}
89+
columnList = new List<SqlTableColumn>(columns);
90+
}
91+
92+
/// <summary>
93+
/// Initializes a new instance of the <see cref="SqlTableColumnCollection"/> class.
94+
/// This is special version it uses provided list as is.
95+
/// </summary>
96+
internal SqlTableColumnCollection(List<SqlTableColumn> columns)
97+
{
98+
columnList = columns;
8099
}
81100
}
82101
}

Orm/Xtensive.Orm/Sql/Dml/SqlContainsTable.cs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,35 +66,40 @@ public SqlQueryExpression UnionAll(ISqlQueryExpression operand)
6666
// Constructors
6767

6868

69-
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columnNames)
69+
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames)
7070
: this(dataTable, freeText, columnNames, ArrayUtils<string>.EmptyArray, null)
7171
{
7272
}
7373

74-
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columnNames, ICollection<string> targetColumnNames)
74+
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames, ICollection<string> targetColumnNames)
7575
: this(dataTable, freeText, columnNames, targetColumnNames, null)
7676
{
7777
}
7878

79-
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columNames, SqlExpression topN)
80-
: this(dataTable, freeText, columNames, ArrayUtils<string>.EmptyArray, topN)
79+
internal SqlContainsTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames, SqlExpression topN)
80+
: this(dataTable, freeText, columnNames, ArrayUtils<string>.EmptyArray, topN)
8181
{
8282
}
8383

84-
internal SqlContainsTable(DataTable dataTable, SqlExpression searchCondition, IEnumerable<string> columnNames, ICollection<string> targetColumnNames, SqlExpression topNByRank)
84+
internal SqlContainsTable(DataTable dataTable, SqlExpression searchCondition, ICollection<string> columnNames, ICollection<string> targetColumnNames, SqlExpression topNByRank)
8585
: base(string.Empty)
8686
{
8787
TargetTable = SqlDml.TableRef(dataTable);
8888
SearchCondition = searchCondition;
8989
TopNByRank = topNByRank;
90-
var targetColumns = new List<SqlTableColumn>();
91-
if (targetColumnNames.Count == 0)
92-
targetColumns.Add(Asterisk);
93-
else
94-
targetColumns = targetColumnNames.Select(cn => SqlDml.TableColumn(this, cn)).ToList();
95-
TargetColumns = new SqlTableColumnCollection(targetColumns);
96-
97-
columns = new SqlTableColumnCollection(columnNames.Select(column=>SqlDml.TableColumn(this, column)).ToList());
90+
var targetColumnCount = targetColumnNames.Count;
91+
if (targetColumnCount == 0) {
92+
TargetColumns = new SqlTableColumnCollection(new List<SqlTableColumn>(1) {Asterisk});
93+
}
94+
else {
95+
var targetColumns = new List<SqlTableColumn>(targetColumnCount);
96+
targetColumns.AddRange(targetColumnNames.Select(columnName => SqlDml.TableColumn(this, columnName)));
97+
TargetColumns = new SqlTableColumnCollection(targetColumns);
98+
}
99+
100+
var columnList = new List<SqlTableColumn>(columnNames.Count);
101+
columnList.AddRange(columnNames.Select(columnName => SqlDml.TableColumn(this, columnName)));
102+
columns = new SqlTableColumnCollection(columnList);
98103
}
99104
}
100105
}

Orm/Xtensive.Orm/Sql/Dml/SqlFreeTextTable.cs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,35 +71,40 @@ public SqlQueryExpression UnionAll(ISqlQueryExpression operand)
7171

7272
// Constructors
7373

74-
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columnNames)
74+
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames)
7575
: this(dataTable, freeText, columnNames, ArrayUtils<string>.EmptyArray, null)
7676
{
7777
}
7878

79-
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columnNames, ICollection<string> targetColumnNames)
79+
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames, ICollection<string> targetColumnNames)
8080
: this(dataTable, freeText, columnNames, targetColumnNames, null)
8181
{
8282
}
8383

84-
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columNames, SqlExpression topN)
85-
: this(dataTable, freeText, columNames, ArrayUtils<string>.EmptyArray, topN)
84+
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames, SqlExpression topN)
85+
: this(dataTable, freeText, columnNames, ArrayUtils<string>.EmptyArray, topN)
8686
{
8787
}
8888

89-
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, IEnumerable<string> columnNames, ICollection<string> targetColumnNames, SqlExpression topNByRank)
89+
internal SqlFreeTextTable(DataTable dataTable, SqlExpression freeText, ICollection<string> columnNames, ICollection<string> targetColumnNames, SqlExpression topNByRank)
9090
: base(string.Empty)
9191
{
9292
TargetTable = SqlDml.TableRef(dataTable);
9393
FreeText = freeText;
9494
TopNByRank = topNByRank;
95-
var targetColumns = new List<SqlTableColumn>();
96-
if (targetColumnNames.Count == 0)
97-
targetColumns.Add(Asterisk);
98-
else
99-
targetColumns = targetColumnNames.Select(cn => SqlDml.TableColumn(this, cn)).ToList();
100-
TargetColumns = new SqlTableColumnCollection(targetColumns);
101-
102-
columns = new SqlTableColumnCollection(columnNames.Select(column=>SqlDml.TableColumn(this, column)).ToList());
95+
var targetColumnCount = targetColumnNames.Count;
96+
if (targetColumnCount == 0) {
97+
TargetColumns = new SqlTableColumnCollection(new List<SqlTableColumn>(1) {Asterisk});
98+
}
99+
else {
100+
var targetColumns = new List<SqlTableColumn>(targetColumnCount);
101+
targetColumns.AddRange(targetColumnNames.Select(columnName => SqlDml.TableColumn(this, columnName)));
102+
TargetColumns = new SqlTableColumnCollection(targetColumns);
103+
}
104+
105+
var columnList = new List<SqlTableColumn>(columnNames.Count);
106+
columnList.AddRange(columnNames.Select(columnName => SqlDml.TableColumn(this, columnName)));
107+
columns = new SqlTableColumnCollection(columnList);
103108
}
104109
}
105110
}

0 commit comments

Comments
 (0)