Skip to content

Commit bc2d598

Browse files
authored
Optimize JoinSequence (#223)
* Optimize `JoinSequence` * Optimize TryFindJoinHint
1 parent cc5c051 commit bc2d598

File tree

3 files changed

+37
-66
lines changed

3 files changed

+37
-66
lines changed

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

+7-20
Original file line numberDiff line numberDiff line change
@@ -266,42 +266,29 @@ public override void Translate(SqlCompilerContext context, SqlJoinExpression nod
266266
_ = output.Append("OUTER APPLY");
267267
return;
268268
}
269-
var joinHint = TryFindJoinHint(context, node);
269+
270+
var right = node.Right;
271+
var joinHint = context.GetTraversalPath()
272+
.OfType<SqlQueryStatement>()
273+
.LastOrDefault()?.Hints.OfType<SqlJoinHint>().FirstOrDefault(hint => hint.Table == right);
270274

271275
Translate(output, node.JoinType);
272276
if (joinHint != null) {
273277
_ = output.AppendSpace().Append(Translate(joinHint.Method));
274278
}
279+
275280
_ = output.Append(" JOIN");
276281
break;
277282
default:
278283
base.Translate(context, node, section);
279284
break;
280285
}
281-
282-
static SqlJoinHint TryFindJoinHint(SqlCompilerContext context, SqlJoinExpression node)
283-
{
284-
SqlQueryStatement statement = null;
285-
for (int i = 0, count = context.GetTraversalPath().Length; i < count; i++) {
286-
if (context.GetTraversalPath()[i] is SqlQueryStatement) {
287-
statement = context.GetTraversalPath()[i] as SqlQueryStatement;
288-
}
289-
}
290-
if (statement == null || statement.Hints.Count == 0) {
291-
return null;
292-
}
293-
294-
var candidate = statement.Hints
295-
.OfType<SqlJoinHint>()
296-
.FirstOrDefault(hint => hint.Table == node.Right);
297-
return candidate;
298-
}
299286
}
300287

301288
/// <inheritdoc/>
302289
public override void Translate(SqlCompilerContext context, SqlQueryExpression node, QueryExpressionSection section)
303290
{
304-
if (node.All && section == QueryExpressionSection.All && (node.NodeType == SqlNodeType.Except || node.NodeType == SqlNodeType.Intersect))
291+
if (node.All && section == QueryExpressionSection.All && (node.NodeType is SqlNodeType.Except or SqlNodeType.Intersect))
305292
return;
306293
base.Translate(context, node, section);
307294
}

Orm/Xtensive.Orm/Sql/Compiler/Internals/JoinSequence.cs

+29-45
Original file line numberDiff line numberDiff line change
@@ -5,71 +5,55 @@
55
// Created: 2012.05.18
66

77
using System.Collections.Generic;
8-
using System.Collections.ObjectModel;
98
using Xtensive.Sql.Dml;
109

1110
namespace Xtensive.Sql.Compiler
1211
{
13-
internal sealed class JoinSequence
12+
internal readonly record struct JoinSequence
13+
(
14+
SqlTable Pivot,
15+
IReadOnlyList<SqlTable> Tables,
16+
IReadOnlyList<SqlJoinType> JoinTypes,
17+
IReadOnlyList<SqlExpression> Conditions
18+
)
1419
{
15-
public SqlTable Pivot { get; private set; }
16-
17-
public IList<SqlTable> Tables { get; private set; }
18-
19-
public IList<SqlJoinType> JoinTypes { get; private set; }
20-
21-
public IList<SqlExpression> Conditions { get; private set; }
22-
2320
public static JoinSequence Build(SqlJoinedTable root)
2421
{
25-
var joins = new List<SqlJoinExpression>();
22+
var joins = new List<SqlJoinExpression>(1);
2623
Traverse(root, joins);
2724

28-
var result = new JoinSequence();
25+
List<SqlTable> tables = new();
26+
List<SqlJoinType> joinTypes = new();
27+
List<SqlExpression> conditions = new();
2928

3029
foreach (var item in joins) {
31-
if (!(item.Left is SqlJoinedTable))
32-
result.Tables.Add(item.Left);
33-
if (!(item.Right is SqlJoinedTable))
34-
result.Tables.Add(item.Right);
35-
result.JoinTypes.Add(item.JoinType);
36-
result.Conditions.Add(item.Expression);
30+
var left = item.Left;
31+
if (!(left is SqlJoinedTable))
32+
tables.Add(left);
33+
var right = item.Right;
34+
if (!(right is SqlJoinedTable))
35+
tables.Add(right);
36+
joinTypes.Add(item.JoinType);
37+
conditions.Add(item.Expression);
3738
}
3839

39-
var pivot = result.Tables[0];
40-
result.Pivot = pivot;
41-
result.Tables.RemoveAt(0);
42-
43-
result.Tables = new ReadOnlyCollection<SqlTable>(result.Tables);
44-
result.JoinTypes = new ReadOnlyCollection<SqlJoinType>(result.JoinTypes);
45-
result.Conditions = new ReadOnlyCollection<SqlExpression>(result.Conditions);
46-
47-
return result;
40+
var pivot = tables[0];
41+
tables.RemoveAt(0);
42+
return new(pivot, tables, joinTypes, conditions);
4843
}
4944

50-
private static void Traverse(SqlJoinedTable root, ICollection<SqlJoinExpression> output)
45+
private static void Traverse(SqlJoinedTable root, List<SqlJoinExpression> output)
5146
{
52-
var left = root.JoinExpression.Left;
53-
var joinedLeft = left as SqlJoinedTable;
54-
if (joinedLeft!=null)
47+
var joinExpression = root.JoinExpression;
48+
if (joinExpression.Left is SqlJoinedTable joinedLeft) {
5549
Traverse(joinedLeft, output);
50+
}
5651

57-
output.Add(root.JoinExpression);
52+
output.Add(joinExpression);
5853

59-
var right = root.JoinExpression.Right;
60-
var joinedRight = right as SqlJoinedTable;
61-
if (joinedRight!=null)
54+
if (joinExpression.Right is SqlJoinedTable joinedRight) {
6255
Traverse(joinedRight, output);
63-
}
64-
65-
66-
// Constructors
67-
68-
private JoinSequence()
69-
{
70-
Tables = new List<SqlTable>();
71-
JoinTypes = new List<SqlJoinType>();
72-
Conditions = new List<SqlExpression>();
56+
}
7357
}
7458
}
7559
}

Orm/Xtensive.Orm/Sql/Compiler/SqlCompiler.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ protected virtual void VisitSelectFrom(SqlSelect node)
16501650
var previous = joinSequence.Pivot;
16511651
previous.AcceptVisitor(this);
16521652

1653-
for (var i = 0; i < joinSequence.Tables.Count; i++) {
1653+
for (int i = 0, n = joinSequence.Tables.Count; i < n; i++) {
16541654
var table = joinSequence.Tables[i];
16551655
var type = joinSequence.JoinTypes[i];
16561656
var condition = joinSequence.Conditions[i];

0 commit comments

Comments
 (0)