Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LightORM.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Project Path="src/Providers/LightORM.Providers.SqlServer/LightORM.Providers.SqlServer.csproj" />
</Folder>
<Folder Name="/test/">
<Project Path="test/BenchmarkTest/BenchmarkTest.csproj" Id="8045558c-2ac8-4242-9f5d-1d1f534a4b27" />
<Project Path="test/LightORMTest.Dameng/LightORMTest.Dameng.csproj" />
<Project Path="test/LightORMTest.MySql/LightORMTest.MySql.csproj" />
<Project Path="test/LightORMTest.Oracle/LightORMTest.Oracle.csproj" />
Expand Down
27 changes: 27 additions & 0 deletions doc/版本日志.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# 版本功能更新记录

## v2026.02.11.1
- ⚡️新增表达式解析缓存功能,默认启用,可以通过`IExpressionContextSetup.SetEnableExpressionCache`进行全局配置
- ⚡️内部高频使用的对象新增对象池
- ⚡️使用日期作为版本号


#### 新版本(开启表达式解析缓存)
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------------------- |----------:|----------:|----------:|--------:|-------:|----------:|
| SelectCTE | 89.498 us | 1.7850 us | 1.6697 us | 10.7422 | 0.4883 | 89.2 KB |
| SelectCTEOptimized | 84.509 us | 1.4743 us | 1.3791 us | 10.2539 | 0.7324 | 85.68 KB |
| SelectWithArrayAccess | 7.799 us | 0.1476 us | 0.1812 us | 0.9460 | 0.1831 | 7.75 KB |
| SelectWithContainArray | 8.465 us | 0.1680 us | 0.2665 us | 0.9155 | 0.1831 | 7.65 KB |
#### 新版本(关闭表达式解析缓存)
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------------------- |-----------:|----------:|----------:|--------:|-------:|----------:|
| SelectCTE | 135.588 us | 2.6832 us | 4.2558 us | 12.2070 | 0.9766 | 103.57 KB |
| SelectCTEOptimized | 129.420 us | 2.5883 us | 3.8741 us | 12.2070 | 0.9766 | 100.88 KB |
| SelectWithArrayAccess | 5.580 us | 0.1010 us | 0.1081 us | 0.9155 | 0.0153 | 7.55 KB |
| SelectWithContainArray | 6.253 us | 0.1131 us | 0.1003 us | 0.8850 | - | 7.27 KB |
#### v3.2.1
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------------------- |-----------:|----------:|----------:|--------:|-------:|----------:|
| SelectCTE | 134.840 us | 2.6678 us | 3.2762 us | 13.6719 | 0.9766 | 115.39 KB |
| SelectCTEOptimized | 126.395 us | 2.4247 us | 2.4900 us | 13.1836 | 0.9766 | 111.5 KB |
| SelectWithArrayAccess | 5.606 us | 0.1063 us | 0.1181 us | 1.0071 | - | 8.3 KB |
| SelectWithContainArray | 6.316 us | 0.1251 us | 0.1489 us | 0.9766 | - | 8.1 KB |
## v3.2.1
- 🛠`DbParameterReader`优化
- 🛠解析表达式时,读取参数值的方式优化,表达式树编译缓存委托后直接调用
Expand Down
1 change: 1 addition & 0 deletions src/LightORM/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ internal static class DebugControl
{
public static readonly bool ShowExpressionResolveDebugInfo = false;
public static readonly bool ShowSqlExecutorDebugInfo = true;
public static readonly bool ShowExpressionHashCodeDebugInfo = true;
}
}
10 changes: 4 additions & 6 deletions src/LightORM/Builder/DeleteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal record DeleteBuilder<T> : SqlBuilder
public List<BatchSqlInfo>? BatchInfos { get; set; }
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
if (result.UseNavigate)
{
Expand All @@ -26,11 +26,9 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
{
continue;
}
var navSqlBuilder = new SelectBuilder
{
IsSubQuery = true,
Level = 1
};
var navSqlBuilder = SelectBuilder.GetSelectBuilder();
navSqlBuilder.IsSubQuery = true;
navSqlBuilder.Level = 1;
navSqlBuilder.SelectedTables.Add(MainTable);
var navInfo = navColumn.NavigateInfo!;
var mainCol = MainTable.GetColumnInfo(navInfo.MainName!);
Expand Down
4 changes: 2 additions & 2 deletions src/LightORM/Builder/InsertBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ internal record InsertBuilder<T> : SqlBuilder
public bool IsReturnIdentity { get; set; }
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
if (expInfo.ResolveOptions?.SqlType == SqlPartial.Insert)
if (expInfo.ResolveOptions.SqlType == SqlPartial.Insert)
{
Members.AddRange(result.Members!);
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Ignore)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Ignore)
{
IgnoreMembers.AddRange(result.Members!);
}
Expand Down
162 changes: 151 additions & 11 deletions src/LightORM/Builder/SelectBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LightORM.Extension;
using LightORM.Performances;
using System.Text;

namespace LightORM.Builder;
Expand All @@ -19,10 +20,9 @@ internal record SelectBuilder : SqlBuilder, ISelectSqlBuilder
{
public SelectBuilder()
{
//DbType = dbType;
IncludeContext = new IncludeContext();
//Indent = new Lazy<string>(() => new string(' ', 4 * Level));
}
public static SelectBuilder GetSelectBuilder() => new();//SelectBuilderPool.Rent();
public string Id { get; } = $"{Guid.NewGuid():N}";
public int PageIndex { get; set; }
public int PageSize { get; set; }
Expand All @@ -46,7 +46,7 @@ public SelectBuilder()
public List<JoinInfo> Joins { get; set; } = [];
public List<string> Having { get; set; } = [];
public List<IncludeInfo> Includes { get; set; } = [];
public IncludeContext IncludeContext { get; set; } = default!;
public IncludeContext IncludeContext { get; set; }

public List<string> GroupBy { get; set; } = [];
public List<string> OrderBy { get; set; } = [];
Expand Down Expand Up @@ -87,7 +87,7 @@ protected override void BeforeResolveExpressions(ResolveContext context)
}
protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
if (result.UseNavigate)
{
Expand Down Expand Up @@ -116,15 +116,15 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
Where.Add(result.SqlString!);
}
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Join)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Join)
{
var joinInfo = Joins.FirstOrDefault(j => j.ExpressionId == expInfo.Id);
if (joinInfo != null)
{
joinInfo.Where = result.SqlString!;
}
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Select)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Select)
{
if (result.UseNavigate)
{
Expand All @@ -146,16 +146,16 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
SelectValue = result.SqlString!;
}
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.GroupBy)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.GroupBy)
{
GroupBy.Add(result.SqlString!);
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.OrderBy)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.OrderBy)
{
OrderBy.Add(result.SqlString!);
AdditionalValue = expInfo.AdditionalParameter;
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Having)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Having)
{
Having.Add(result.SqlString!);
}
Expand Down Expand Up @@ -251,17 +251,21 @@ private void BuildFromString(StringBuilder sql, ICustomDatabase database)
public override string ToSqlString(ICustomDatabase database)
{
//SubQuery?.ResolveExpressions();
StringBuilder sql = new();
var estimatedSize = EstimateSqlLength();
StringBuilder sql = new(estimatedSize);
Build(sql, database, Level);
HandleSqlParameters(sql, database);
sql.Trim();
return sql.ToString();
var sqlString = sql.ToString();
//SelectBuilderPool.Return(this);
return sqlString;

}

public void Build(StringBuilder sql, ICustomDatabase database, int currentLevel)
{
ResolveExpressions(database);

var ident = new string(' ', 4 * currentLevel);
if (InsertInfo.HasValue)
{
Expand Down Expand Up @@ -417,4 +421,140 @@ public void Build(StringBuilder sql, ICustomDatabase database, int currentLevel)
}
}
}

int EstimateSqlLength(int currentLevel = 0)
{
int total = 0;
const int indentPerLevel = 4;
var indent = indentPerLevel * currentLevel;

// SELECT
total += indent + 10 + (IsDistinct ? 9 : 0);
if (SelectValue != null) total += SelectValue.Length;
total += 2; // \n

// FROM / SubQuery
if (SubQuery != null)
{
total += indent + 7;
total += SubQuery.EstimateSqlLength(currentLevel + 1);
total += indent + 3;
if (MainTable.Alias != null) total += MainTable.Alias.Length;
total += 2;
}
else
{
total += indent + 5;
for (int i = 0; i < SelectedTables.Count; i++)
{
if (i > 0) total += 2; // ", "
var t = SelectedTables[i];
total += t.TableName.Length + 2;
if (t.Alias != null) total += 1 + t.Alias.Length;
}
total += 1; // \n
}

// JOINs
for (int i = 0; i < Joins.Count; i++)
{
var join = Joins[i];
total += indent + 10; // "INNER JOIN "
if (join.IsSubQuery && join.SubQuery != null)
{
total += join.SubQuery.EstimateSqlLength(currentLevel + 1);
}
else if (join.EntityInfo != null)
{
total += join.EntityInfo.TableName.Length + 2;
if (join.EntityInfo.Alias != null)
total += 1 + join.EntityInfo.Alias.Length;
}
total += 4; // " ON "
if (join.Where != null) total += join.Where.Length;
else total += 10;
total += 2; // \n
}

// WHERE
if (Where.Count > 0)
{
total += indent + 7;
for (int i = 0; i < Where.Count; i++)
{
if (i > 0) total += 5; // " AND "
total += Where[i].Length;
}
total += 1; // \n
}

// GROUP BY
if (GroupBy.Count > 0)
{
total += indent + 12;
if (IsRollup) total += 9;
for (int i = 0; i < GroupBy.Count; i++)
{
if (i > 0) total += 2; // ", "
total += GroupBy[i].Length;
}
if (IsRollup) total += 1;
total += 1; // \n
}

// ORDER BY
if (OrderBy.Count > 0)
{
total += indent + 10;
for (int i = 0; i < OrderBy.Count; i++)
{
if (i > 0) total += 2;
total += OrderBy[i].Length;
}
// ⚠️ AdditionalValue: 避免 ToString()
// 如果你知道它通常是 string/int,可特殊处理:
if (AdditionalValue is string s) total += s.Length;
else if (AdditionalValue is not null)
{
// 保守估计:最多 10 个字符(如 "DESC")
total += 10;
}
total += 1; // \n
}

// Paging (Take/Skip)
if (Take > 0)
{
total += 50; // 保守估计 LIMIT/OFFSET/FETCH
}

// CTE (WITH ...)
if (TempViews.Count > 0)
{
total += 5; // "WITH "
foreach (var view in TempViews)
{
total += view.EstimateSqlLength(currentLevel + 1);
total += 2; // "),"
}
}

// UNION
foreach (var union in Unions)
{
total += indent + 12; // "UNION ALL\n"
total += union.SqlBuilder.EstimateSqlLength(currentLevel);
}

// Temp wrapper: " name AS (\n ... \n)"
if (IsTemp)
{
total += (TempName?.Length ?? 10) + 6; // " name AS ("
total += 2; // "\n...\n)"
}

// 安全边际
return Math.Max(64, (int)(total * 1.2) + 50);
}
}

9 changes: 5 additions & 4 deletions src/LightORM/Builder/SqlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace LightORM.Builder;
internal abstract record SqlBuilder : ISqlBuilder
{
public static string N { get; } = Environment.NewLine;

public ExpressionInfoProvider Expressions { get; } = new ExpressionInfoProvider();
public TableInfo MainTable => SelectedTables[0];
public List<TableInfo> SelectedTables { get; set; } = [];
Expand Down Expand Up @@ -97,15 +96,17 @@ protected void ResolveExpressions(ICustomDatabase database)
foreach (var item in Expressions.ExpressionInfos.Values.Where(item => !item.Completed))
{
//item.ResolveOptions!.DbType = DbType;
item.ResolveOptions!.ParameterPartialIndex = index;
var result = item.Expression.Resolve(item.ResolveOptions!, ResolveCtx);
//item.ResolveOptions = item.ResolveOptions with { ParameterPartialIndex = index };
item.ResolveOptions.ParameterPartialIndex = index;
var result = item.Expression.Resolve(item.ResolveOptions, ResolveCtx);
item.Completed = true;
if (!string.IsNullOrEmpty(item.Template))
{
result.SqlString = string.Format(item.Template, result.SqlString);
}
HandleResult(database, item, result);
DbParameterInfos.AddRange(result.DbParameters ?? []);
if (result.DbParameters != null)
DbParameterInfos.AddRange(result.DbParameters);
index++;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/LightORM/Builder/UpdateBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ internal record UpdateBuilder<T> : SqlBuilder

protected override void HandleResult(ICustomDatabase database, ExpressionInfo expInfo, ExpressionResolvedResult result)
{
if (expInfo.ResolveOptions?.SqlType == SqlPartial.Where)
if (expInfo.ResolveOptions.SqlType == SqlPartial.Where)
{
Where.Add(result.SqlString!);
WhereMembers.AddRange(result?.Members?.Distinct() ?? []);
WhereMembers.AddRange(result.Members?.Distinct() ?? []);
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Update)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Update)
{
if (expInfo.AdditionalParameter is null)
{
Expand All @@ -46,7 +46,7 @@ protected override void HandleResult(ICustomDatabase database, ExpressionInfo ex
}
}
}
else if (expInfo.ResolveOptions?.SqlType == SqlPartial.Ignore)
else if (expInfo.ResolveOptions.SqlType == SqlPartial.Ignore)
{
IgnoreMembers.AddRange(result.Members!);
//IgnoreMembers = new(result.Members!)
Expand Down
2 changes: 1 addition & 1 deletion src/LightORM/ExpressionSql/ExpressionCoreSql.Union.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public IExpSelect<T> FromQuery<T>(IExpSelect<T> select)

public IExpSelect<T> FromTemp<T>(IExpTemp<T> temp)
{
var builder = new SelectBuilder();
var builder = SelectBuilder.GetSelectBuilder();
builder.HandleTempsRecursion(temp.SqlBuilder);
builder.SelectedTables.Add(temp.ResultTable);
return new SelectProvider1<T>(Ado, builder);
Expand Down
Loading
Loading