虽然我用 SSIS 标记了这个问题,但它不一定是我问题的核心;因此,如果您通常熟悉 .NET 反射和代码性能问题,请继续阅读,因为您可能会有所帮助!
但特别是,相关代码将被执行多次(即针对每行的数据源)这一事实是关键。
我正在更新一个预先存在的自定义数据流控制。
对于行中的每一列,代码必须在Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer
实例(行)上执行特定方法,具体取决于(列)SSIS 数据类型。
例如,
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
...
while (!buffer.EndOfRowset && buffer.NextRow())
{
...
someStringAtColumn1 = buffer.GetString(1);
someIntAtColumn2 = buffer.GetInt16(2);
someBoolAtColumn3 = buffer.GetBoolean(3);
// And so on, for up to ~25 different types....
}
...
}
但是,控件需要是动态的,因此我们在设计时不知道每列在运行时将是哪种类型。
为此,在SSIS Junkie SSIS 上发布的模式:用于填充管道缓冲区列的通用方法已被使用(并且有效)。总之,这使用 aSWITCH (buffer.GetColumnInfo(columnIndex).DataType)
来决定调用 ~25 个方法中的哪一个buffer
。
所以,我的问题:
SWITCH
是否对每一行(可能数百万)的每一列(每个表的数量不同,但假设平均 10 列)重复此语句,可能会导致显着的性能影响(就处理时间而言)?最好在每个表的基础上(即在逐行处理开始之前)为每列后期绑定到正确的方法,然后对每一列执行特定于列的后期绑定方法(在逐行处理期间)?
我正在考虑的方法是这样的:
// Set up per-column late-bound methods, once, prior to processing the rows
System.Reflection.MethodInfo[] lateBoundMethods;
//Psuedo code here for brevity...
foreach column in tableDefinition {
lateBoundMethods[i++] = getColumnSpecificGetValueMethod(column.DataType);
}
//End of psuedo code
private System.Reflection.MethodInfo getColumnSpecificGetValueMethod(DataType dataType)
{
string methodName = "";
switch (dataType)
{
case DataType.DT_BOOL:
methodName = "GetBoolean";
break;
case DataType.DT_BYTES:
methodName = "GetBytes";
break;
case DataType.DT_CY:
methodName = "GetDecimal";
break;
...
case DataType.DT_WSTR:
methodName = "GetString";
break;
default:
return null; //TODO: Throw an exception?
}
System.Reflection.MethodInfo methodInfo = typeof(PipelineBuffer).GetMethod(
methodName,
System.Reflection.BindingFlags.ExactBinding |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public);
return methodInfo;
}
private object getValueFromBuffer(PipelineBuffer buffer, int columnIndex)
{
if (buffer.IsNull(columnIndex))
{
return null;
}
return lateBoundMethods[columnIndex].Invoke(buffer, new object[] { columnIndex});
}
然后,在行处理期间,对于每一列我只需要调用
Object columnValue = getValueFromBuffer(buffer, columnIndex);
.
所以我猜问题 2 归结为“针对已经绑定的执行 a会比执行大开关/案例更快吗?.Invoke
MethodInfo
”。
编辑:我很欣赏反射通常被认为是缓慢的。但是根据上面的大胆问题,我不清楚反射的哪些部分是缓慢的。我很高兴在执行前设置阶段表现不佳,只要调用后期绑定方法比在处理行时选择要调用的方法更快。因此,对于任何说明这会很慢的答案,您能否澄清一下,您认为调用后期绑定方法会很慢,而不是识别要绑定哪个方法的任务。
我意识到没有答案会像运行一些测试那样确定......但我在投入大量精力之前一直在寻找一些(合理的)权威指示,因为将 ETL 部署到我们的 TEST 环境中进行性能测试并非易事.
此外,我愿意接受有关其他更好方法的建议。
感谢您的时间和投入!