我希望优化这段代码。它将处理15000 - 20000行。现在我有9000行,大约需要30秒。我知道字符串连接很慢但我不知道如何以另一种方式进行。
//
// Check if composite primary keys existe in database
//
string strSelect = "SELECT * FROM " + _strTableName + " WHERE ";
for (int i = 0; i < strCompositeKeyField.Length; i++)
{
bool boolKeyProcess = false;
strSelect += _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " = ";
DataColumn thisColomn = _dsProcessDataFromFileAndPutInDataSetDataSet.Tables["Repartition"].Columns[_strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]];
//_strProcessDataFromFileAndPutInDataSetLog += "Debug: Composite key : " + _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " dataType : " + thisColomn.DataType.ToString() + " arrayListCompositeKeyIndex[i] = " + arrayListCompositeKeyIndex[i] + " \n";
// check if field is datetime to make convertion
if (thisColomn.DataType.ToString() == "System.DateTime")
{
DateTime thisDateTime = DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]], _strDateConvertion, null);
strSelect += "'" + thisDateTime.ToString() + "'";
boolKeyProcess = true;
}
// check if field a string to add ''
else if (thisColomn.DataType.ToString() == "System.String")
{
strSelect += "'" + strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]] + "'";
boolKeyProcess = true;
}
// check if field need hour to second converstion
else
{
for (int j = 0; j < strHourToSecondConverstionField.Length; j++)
{
if (strCompositeKeyField[i] == strHourToSecondConverstionField[j])
{
DateTime thisDateTime = DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]], _strHourConvertion, System.Globalization.CultureInfo.CurrentCulture);
strSelect += thisDateTime.TimeOfDay.TotalSeconds.ToString();
boolKeyProcess = true;
}
}
}
// if not allready process process as normal
if (!boolKeyProcess)
{
strSelect += strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]];
}
// Add " AND " if not last field
if (i != strCompositeKeyField.Length - 1)
{
strSelect += " AND ";
}
}
//_strProcessDataFromFileAndPutInDataSetLog += "Debug: SELECT = " + strSelect + "\n";
SqlDataAdapter AdapterCheckCompositePrimaryKeys = new SqlDataAdapter(strSelect, _scProcessDataFrinFileAndPutInDataSetSqlConnection);
DataSet DataSetCheckCompositePrimaryKeys = new DataSet();
AdapterCheckCompositePrimaryKeys.Fill(DataSetCheckCompositePrimaryKeys, "PrimaryKey");
答案 0 :(得分:4)
你绝对应该看一下StringBuilder - 它可以为这样的场景带来奇迹。在这种情况下,我会使用AppendFormat和Append的混合。我倾向于喜欢AppendFormat来使字符串更容易理解。
//
// Check if composite primary keys existe in database
//
StringBuilder strSelect = "SELECT * FROM " + _strTableName + " WHERE ";
for (int i = 0; i < strCompositeKeyField.Length; i++)
{
bool boolKeyProcess = false;
strSelect.AppendFormat("{0} =",
_strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]);
DataColumn thisColomn =
_dsProcessDataFromFileAndPutInDataSetDataSet
.Tables["Repartition"]
.Columns[_strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]]];
//_strProcessDataFromFileAndPutInDataSetLog += "Debug: Composite key : " + _strHeaderLineSplitedArray[(int)arrayListCompositeKeyIndex[i]] + " dataType : " + thisColomn.DataType.ToString() + " arrayListCompositeKeyIndex[i] = " + arrayListCompositeKeyIndex[i] + " \n";
// check if field is datetime to make convertion
if (thisColomn.DataType.ToString() == "System.DateTime")
{
DateTime thisDateTime =
DateTime.ParseExact(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]],
_strDateConvertion, null);
strSelect.AppendFormat("'{0}'", thisDateTime.ToString());
boolKeyProcess = true;
}
// check if field a string to add ''
else if (thisColomn.DataType.ToString() == "System.String")
{
strSelect.AppendFormat("'{0}'",
strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]]);
boolKeyProcess = true;
}
// check if field need hour to second converstion
else
{
for (int j = 0; j < strHourToSecondConverstionField.Length; j++)
{
if (strCompositeKeyField[i] == strHourToSecondConverstionField[j])
{
DateTime thisDateTime = DateTime.ParseExact(
strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]],
_strHourConvertion,
System.Globalization.CultureInfo.CurrentCulture);
strSelect.Append(thisDateTime.TimeOfDay.TotalSeconds.ToString());
boolKeyProcess = true;
}
}
}
// if not allready process process as normal
if (!boolKeyProcess)
{
strSelect.Append(strReadDataLineSplited[(int)arrayListCompositeKeyIndex[i]]);
}
// Add " AND " if not last field
if (i != strCompositeKeyField.Length - 1)
{
strSelect.Append(" AND ");
}
}
//_strProcessDataFromFileAndPutInDataSetLog += "Debug: SELECT = " + strSelect + "\n";
SqlDataAdapter AdapterCheckCompositePrimaryKeys = new SqlDataAdapter(strSelect.ToString(), _scProcessDataFrinFileAndPutInDataSetSqlConnection);
DataSet DataSetCheckCompositePrimaryKeys = new DataSet();
AdapterCheckCompositePrimaryKeys.Fill(DataSetCheckCompositePrimaryKeys, "PrimaryKey");
答案 1 :(得分:2)
使用StringBuilder及其Append()方法。
答案 2 :(得分:1)
使用StringBuilder而不是字符串连接。
答案 3 :(得分:1)
使用StringBuilder进行字符串操作,如strSelect + = ... 而是使用stringBuilder.Append(“...”);
答案 4 :(得分:1)
您是否尝试过StringBuilder对象? http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx
答案 5 :(得分:1)
要回答您的直接问题,您几乎肯定会受益于使用StringBuilder
来构建字符串,然后使用ToString()来结束。
但是,如果你能给我们概述一下这个意图(所以我们不必逐渐推断它),我们可能会建议一个更好的方法。
答案 6 :(得分:1)
快速浏览一下,有一件事就是你应该使用StringBuilder类来构建字符串,而不是连续地连接到你的strSelect字符串变量。摘自链接的MSDN文章:
String或的串联操作的性能 StringBuilder对象取决于方式 通常会发生内存分配。一个 字符串连接操作始终 分配内存,而a StringBuilder连接操作 只有分配内存 StringBuilder对象缓冲区也是如此 小到容纳新数据。 因此,String类是 最好是串联 操作如果是固定数量的String 对象是连接的。在那里面 个案,个别串联 甚至可以将操作合并到一起 编译器的单个操作。一个 StringBuilder对象更适合 一个连接操作,如果一个 任意数量的字符串 级联;例如,如果一个循环 连接随机数 用户输入字符串。
答案 7 :(得分:1)
我是一个数据库人,所以希望我听起来不像白痴,但你可以使用StringBuilder类吗?我不知道是否需要.NET框架。
答案 8 :(得分:0)
您已收到很多使用StringBuilder的好建议。为了提高您的性能,并且因为您期望得到大的字符串结果,我建议您选择一个良好的初始容量来减少内部字符串缓冲区需要扩展的次数。
StringBuilder strSelect = new StringBuilder("SELECT * FROM " + _strTableName + " WHERE ", 8192);
请注意,我在此处选择了8192个字符,但如果您确实要在条件中添加“9000”行数据,则可能需要将其初始化为更大的数字。找出你的典型尺寸,并将其容量设置为高于该值的一小部分。
StringBuilder的工作方式是,当您附加到字符串并达到当前容量时,它必须创建一个新缓冲区并将旧缓冲区的内容复制到新缓冲区,然后附加新字符。为了优化性能,新缓冲区将是旧尺寸的两倍。现在,默认初始容量为16个字符或初始化字符串的大小。如果结果字符串长度为5000个字符,则使用默认大小创建的StringBuilder必须扩展9次 - 这需要新的内存分配并复制所有以前的字符!但是,如果您知道这会定期发生并创建具有适当容量的StringBuilder,则不会有额外的分配或副本。
通常,您不必担心对象的内部操作,但有时您会考虑这样的性能。由于StringBuilder确实为您提供了特定推荐初始容量的方法,因此可以利用它。您不知道双重/复制算法将来是否会发生变化,初始默认容量是否会发生变化,但您对初始容量的规范将继续分配正确大小的构建器 - 因为这是公共合同的一部分。