Skip to content

Commit 65b45a2

Browse files
authored
Merge pull request #237 from servicetitan/upstream/SqlTruncateTable
Optimize work with temporary tables when translating `.In()` extension - SqlInsert supports insertion of multiple rows at once; - SqlInsert Values dictionary became obsolete, all usages of it are eliminated, add values as rows instead; - use of Truncate instead of Delete for temporary table clean-up; - improves population of temporary tables by using 2 grades of multi-row inserts; - new property DomainConfiguration.MaxNumberOfConditions can define limit when .In() extension with IncludeAlgorithm.Auto will decide to use temporary table instead of IN clause, Default value is 256 (as it was before) and can be found among WellKnown constants. Old WellKnown.MaxNumberOfConditions is Obsolete Use WellKnown.DefaultMaxNumberOfConditions or DomainConfiguration.MaxNumberOfConditions.
2 parents 5015c2e + 11b0f6d commit 65b45a2

File tree

56 files changed

+1388
-631
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1388
-631
lines changed

Extensions/Xtensive.Orm.BulkOperations/Internals/AddValueContext.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using System.Linq.Expressions;
23
using Xtensive.Linq;
34
using Xtensive.Orm.Model;
@@ -14,9 +15,9 @@ internal class AddValueContext
1415
public LambdaExpression Lambda { get; set; }
1516
public SetStatement Statement { get; set; }
1617

17-
public FieldInfo Field { get; set; }
18+
public FieldInfo Field => Descriptor.Field;
1819

19-
public bool SubqueryExists { get; set; }
20+
public Dictionary<SqlColumn, SqlExpression> Values { get; set; }
2021

2122
public object EvalLambdaBody() =>
2223
Lambda.Body is ConstantExpression ce

Extensions/Xtensive.Orm.BulkOperations/Internals/BaseSqlVisitor.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.Linq;
23
using Xtensive.Sql;
34
using Xtensive.Sql.Ddl;
45
using Xtensive.Sql.Dml;
@@ -247,6 +248,10 @@ public virtual void Visit(SqlDropView node)
247248
{
248249
}
249250

251+
public virtual void Visit(SqlTruncateTable node)
252+
{
253+
}
254+
250255
public virtual void Visit(SqlDynamicFilter node)
251256
{
252257
foreach (SqlExpression expression in node.Expressions)
@@ -314,9 +319,12 @@ public virtual void Visit(SqlInsert node)
314319
{
315320
VisitInternal(node.From);
316321
VisitInternal(node.Into);
317-
foreach (var pair in node.Values) {
318-
VisitInternal(pair.Key);
319-
VisitInternal(pair.Value);
322+
323+
foreach(var row in node.ValueRows) {
324+
foreach(var columnvalue in row.Zip(node.ValueRows.Columns)) {
325+
VisitInternal(columnvalue.Second);
326+
VisitInternal(columnvalue.First);
327+
}
320328
}
321329
}
322330

Extensions/Xtensive.Orm.BulkOperations/Internals/SetOperation.cs

Lines changed: 163 additions & 152 deletions
Large diffs are not rendered by default.

Extensions/Xtensive.Orm.BulkOperations/Internals/SetStatement.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using System;
2+
using System.Collections.Generic;
23
using Xtensive.Sql;
34
using Xtensive.Sql.Dml;
45

@@ -20,9 +21,9 @@ public override SqlTable Table
2021
get { return insert.Into; }
2122
}
2223

23-
public override void AddValue(SqlTableColumn column, SqlExpression value)
24+
public override void AddValues(Dictionary<SqlColumn, SqlExpression> values)
2425
{
25-
insert.Values.Add(column, value);
26+
insert.ValueRows.Add(values);
2627
}
2728
}
2829

@@ -42,30 +43,33 @@ public override SqlTable Table
4243
get { return update.Update; }
4344
}
4445

45-
public override void AddValue(SqlTableColumn column, SqlExpression value)
46+
public override void AddValues(Dictionary<SqlColumn, SqlExpression> values)
4647
{
47-
update.Values.Add(column, value);
48+
if (update.Values.Count!=0) {
49+
throw new InvalidOperationException("Update values have already been initialized");
50+
}
51+
foreach (var keyValue in values) {
52+
update.Values.Add((SqlTableColumn)keyValue.Key, keyValue.Value);
53+
}
4854
}
4955
}
5056

5157
#endregion
5258

5359
private SqlQueryStatement statement;
5460

55-
public static SetStatement Create(SqlQueryStatement statement)
61+
public static SetStatement Create(SqlUpdate updateStatement)
5662
{
57-
SetStatement result;
58-
if (statement is SqlUpdate)
59-
result = new Update();
60-
else if (statement is SqlInsert)
61-
result = new Insert();
62-
else
63-
throw new InvalidOperationException("Statement must be SqlUpdate or SqlInsert");
64-
result.statement = statement;
65-
return result;
63+
return new Update() { statement = updateStatement };
64+
}
65+
66+
public static SetStatement Create(SqlInsert insertStatement)
67+
{
68+
return new Insert() { statement = insertStatement };
6669
}
6770

6871
public abstract SqlTable Table { get; }
69-
public abstract void AddValue(SqlTableColumn column, SqlExpression value);
72+
73+
public abstract void AddValues(Dictionary<SqlColumn, SqlExpression> values);
7074
}
7175
}

Extensions/Xtensive.Orm.BulkOperations/Internals/WellKnownMembers.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2020 Xtensive LLC.
1+
// Copyright (C) 2020-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

@@ -16,7 +16,9 @@ internal static class WellKnownMembers
1616
public static readonly Type FuncOfTArgTResultType = typeof(Func<,>);
1717

1818
public static readonly Type IncludeAlgorithmType = typeof(IncludeAlgorithm);
19+
public static readonly Type QueryableType = typeof(Queryable);
1920
public static readonly Type QueryableExtensionsType = typeof(QueryableExtensions);
21+
2022
public const string InMethodName = nameof(QueryableExtensions.In);
2123

2224
public static readonly MethodInfo TranslateQueryMethod =

Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/v09/ServerInfoProvider.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ public override EntityInfo GetTriggerInfo()
4040
{
4141
EntityInfo triggerInfo = new EntityInfo();
4242
triggerInfo.MaxIdentifierLength = MaxIdentifierLength;
43-
triggerInfo.AllowedDdlStatements = DdlStatements.All;
43+
triggerInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
4444
return triggerInfo;
4545
}
4646

4747
public override EntityInfo GetStoredProcedureInfo()
4848
{
4949
EntityInfo procedureInfo = new EntityInfo();
5050
procedureInfo.MaxIdentifierLength = MaxIdentifierLength;
51-
procedureInfo.AllowedDdlStatements = DdlStatements.All;
51+
procedureInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
5252
return procedureInfo;
5353
}
5454

@@ -61,7 +61,7 @@ public override EntityInfo GetDatabaseInfo()
6161
{
6262
EntityInfo databaseInfo = new EntityInfo();
6363
databaseInfo.MaxIdentifierLength = MaxIdentifierLength;
64-
databaseInfo.AllowedDdlStatements = DdlStatements.All;
64+
databaseInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
6565
return databaseInfo;
6666
}
6767

@@ -70,23 +70,23 @@ public override ColumnInfo GetColumnInfo()
7070
ColumnInfo columnInfo = new ColumnInfo();
7171
columnInfo.MaxIdentifierLength = MaxIdentifierLength;
7272
columnInfo.Features = ColumnFeatures.Identity | ColumnFeatures.Computed;
73-
columnInfo.AllowedDdlStatements = DdlStatements.All;
73+
columnInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
7474
return columnInfo;
7575
}
7676

7777
public override EntityInfo GetViewInfo()
7878
{
7979
EntityInfo viewInfo = new EntityInfo();
8080
viewInfo.MaxIdentifierLength = MaxIdentifierLength;
81-
viewInfo.AllowedDdlStatements = DdlStatements.All;
81+
viewInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
8282
return viewInfo;
8383
}
8484

8585
public override EntityInfo GetSchemaInfo()
8686
{
8787
EntityInfo schemaInfo = new EntityInfo();
8888
schemaInfo.MaxIdentifierLength = MaxIdentifierLength;
89-
schemaInfo.AllowedDdlStatements = DdlStatements.All;
89+
schemaInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
9090
return schemaInfo;
9191
}
9292

@@ -114,7 +114,7 @@ public override CheckConstraintInfo GetCheckConstraintInfo()
114114
checkConstraintInfo.MaxIdentifierLength = MaxIdentifierLength;
115115
checkConstraintInfo.MaxExpressionLength = 4000;
116116
checkConstraintInfo.Features = CheckConstraintFeatures.None;
117-
checkConstraintInfo.AllowedDdlStatements = DdlStatements.All;
117+
checkConstraintInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
118118
return checkConstraintInfo;
119119
}
120120

@@ -123,7 +123,7 @@ public override PrimaryKeyConstraintInfo GetPrimaryKeyInfo()
123123
var primaryKeyInfo = new PrimaryKeyConstraintInfo();
124124
primaryKeyInfo.MaxIdentifierLength = MaxIdentifierLength;
125125
primaryKeyInfo.Features = PrimaryKeyConstraintFeatures.Clustered;
126-
primaryKeyInfo.AllowedDdlStatements = DdlStatements.All;
126+
primaryKeyInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
127127
return primaryKeyInfo;
128128
}
129129

@@ -132,7 +132,7 @@ public override UniqueConstraintInfo GetUniqueConstraintInfo()
132132
var uniqueConstraintInfo = new UniqueConstraintInfo();
133133
uniqueConstraintInfo.MaxIdentifierLength = MaxIdentifierLength;
134134
uniqueConstraintInfo.Features = UniqueConstraintFeatures.Clustered | UniqueConstraintFeatures.Nullable;
135-
uniqueConstraintInfo.AllowedDdlStatements = DdlStatements.All;
135+
uniqueConstraintInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
136136
return uniqueConstraintInfo;
137137
}
138138

@@ -142,7 +142,7 @@ public override IndexInfo GetIndexInfo()
142142
indexInfo.MaxIdentifierLength = MaxIdentifierLength;
143143
indexInfo.MaxNumberOfColumns = 16;
144144
indexInfo.MaxLength = 900;
145-
indexInfo.AllowedDdlStatements = DdlStatements.All;
145+
indexInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
146146
indexInfo.Features =
147147
IndexFeatures.Clustered |
148148
IndexFeatures.FillFactor |
@@ -163,7 +163,7 @@ public override ForeignKeyConstraintInfo GetForeignKeyConstraintInfo()
163163
ForeignKeyConstraintActions.Cascade |
164164
ForeignKeyConstraintActions.SetDefault |
165165
ForeignKeyConstraintActions.SetNull;
166-
referenceConstraintInfo.AllowedDdlStatements = DdlStatements.All;
166+
referenceConstraintInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
167167
return referenceConstraintInfo;
168168
}
169169

Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/v3/ServerInfoProvider.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,23 @@ public override EntityInfo GetViewInfo()
7373
{
7474
EntityInfo viewInfo = new EntityInfo();
7575
viewInfo.MaxIdentifierLength = MaxIdentifierLength;
76-
viewInfo.AllowedDdlStatements = DdlStatements.All;
76+
viewInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
7777
return viewInfo;
7878
}
7979

8080
public override EntityInfo GetSchemaInfo()
8181
{
8282
EntityInfo schemaInfo = new EntityInfo();
8383
schemaInfo.MaxIdentifierLength = MaxIdentifierLength;
84-
schemaInfo.AllowedDdlStatements = DdlStatements.All;
84+
schemaInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
8585
return schemaInfo;
8686
}
8787

8888
public override TableInfo GetTableInfo()
8989
{
9090
var tableInfo = new TableInfo();
9191
tableInfo.MaxIdentifierLength = MaxIdentifierLength;
92-
tableInfo.AllowedDdlStatements = DdlStatements.All;
92+
tableInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
9393
tableInfo.PartitionMethods = PartitionMethods.List | PartitionMethods.Range | PartitionMethods.Hash;
9494
return tableInfo;
9595
}
@@ -98,7 +98,7 @@ public override TemporaryTableInfo GetTemporaryTableInfo()
9898
{
9999
var temporaryTableInfo = new TemporaryTableInfo();
100100
temporaryTableInfo.MaxIdentifierLength = MaxIdentifierLength;
101-
temporaryTableInfo.AllowedDdlStatements = DdlStatements.All;
101+
temporaryTableInfo.AllowedDdlStatements = DdlStatements.All & ~DdlStatements.Truncate;
102102
temporaryTableInfo.Features = TemporaryTableFeatures.Local;
103103
return temporaryTableInfo;
104104
}

Orm/Xtensive.Orm.Tests.Framework/TestHelper.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
// Copyright (C) 2008-2021 Xtensive LLC.
1+
// Copyright (C) 2008-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alex Yakunin
55
// Created: 2008.02.09
66

77
using System;
8+
using System.Collections.Generic;
89
using System.Threading;
10+
using Xtensive.Sql.Dml;
11+
912

1013
namespace Xtensive.Orm.Tests
1114
{
@@ -166,6 +169,17 @@ public static TimeOnly AdjustTimeOnlyForProvider(this TimeOnly origin, StoragePr
166169
var newTicks = ticks - (ticks % divider.Value);
167170
return new TimeOnly(newTicks);
168171
}
172+
173+
public static void AddValueRow(this SqlInsert insert, in (SqlColumn column, SqlExpression value) first, params (SqlColumn column, SqlExpression value)[] additional)
174+
{
175+
var additional1 = additional ?? Array.Empty<(SqlColumn,SqlExpression)>();
176+
var row = new Dictionary<SqlColumn, SqlExpression>(1 + additional1.Length);
177+
row.Add(first.column, first.value);
178+
foreach (var keyValue in additional1) {
179+
row.Add(keyValue.column, keyValue.value);
180+
}
181+
insert.ValueRows.Add(row);
182+
}
169183
#endif
170184
}
171185
}

Orm/Xtensive.Orm.Tests.Sql/ChinookSchemaCreator.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2019-2022 Xtensive LLC.
1+
// Copyright (C) 2019-2023 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Kulakov
@@ -325,13 +325,14 @@ private static void ExecuteInsert(SqlConnection connection, Table table, Diction
325325
{
326326
var tableRef = SqlDml.TableRef(table);
327327
var insertQuery = SqlDml.Insert(tableRef);
328+
var row = new Dictionary<SqlColumn, SqlExpression>(values.Count);
328329
foreach (var nameValue in values) {
329330
var value = nameValue.Value != null
330331
? (SqlExpression) SqlDml.Literal(nameValue.Value)
331332
: SqlDml.Null;
332-
insertQuery.Values.Add(tableRef[nameValue.Key], value);
333+
row.Add(tableRef[nameValue.Key], value);
333334
}
334-
335+
insertQuery.ValueRows.Add(row);
335336
using var command = connection.CreateCommand(insertQuery);
336337
Console.WriteLine(command.CommandText);
337338
_ = command.ExecuteNonQuery();

Orm/Xtensive.Orm.Tests.Sql/CloneTests.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2003-2023 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44

55
using NUnit.Framework;
66
using System;
7+
using System.Linq;
78
using System.Collections.Generic;
89
using Xtensive.Sql;
910
using Xtensive.Sql.Dml;
@@ -597,18 +598,19 @@ public void SqlInsertCloneTest()
597598
{
598599
SqlTableRef t = SqlDml.TableRef(table1);
599600
SqlInsert i = SqlDml.Insert(t);
600-
i.Values[t[0]] = 1;
601-
i.Values[t[1]] = "Anonym";
601+
i.AddValueRow(( t[0], 1 ), ( t[1], "Anonym" ));
602602
i.Hints.Add(SqlDml.FastFirstRowsHint(10));
603603
SqlInsert iClone = (SqlInsert)i.Clone();
604604

605605
Assert.AreNotEqual(i, iClone);
606606
Assert.AreNotEqual(i.Into, iClone.Into);
607607
Assert.AreEqual(i.NodeType, iClone.NodeType);
608-
Assert.AreEqual(i.Values.Count, iClone.Values.Count);
609-
foreach (KeyValuePair<SqlColumn, SqlExpression> p in i.Values) {
610-
Assert.IsFalse(iClone.Values.ContainsKey(p.Key));
611-
Assert.IsFalse(iClone.Values.ContainsValue(p.Value));
608+
Assert.AreEqual(i.ValueRows.Count, iClone.ValueRows.Count);
609+
Assert.AreEqual(i.ValueRows.Columns.Count, iClone.ValueRows.Columns.Count);
610+
for(var indx = 0; indx < i.ValueRows.Count; indx++) {
611+
var iRow = i.ValueRows[indx];
612+
var iClonedRow = iClone.ValueRows[indx];
613+
Assert.IsFalse(iRow.SequenceEqual(iClonedRow));
612614
}
613615
Assert.AreEqual(i.Hints.Count, iClone.Hints.Count);
614616
}

0 commit comments

Comments
 (0)