C# 优化LINQ查找查询

C# 优化LINQ查找查询,c#,sql,performance,linq,query-optimization,C#,Sql,Performance,Linq,Query Optimization,我正在编写一个报告,它需要来自两个不同位置的数据,一个是SQL Server数据库,另一个是DB2数据库,我用下面的代码完成了这项工作 这是我的SQL Server数据库: private List<MerchantTerminal> GetListOfActiveTerminals(Int64 corebankingRecord, Int64 terminalRecord, bool dialup, bool ethernet, bool cellular, bool wifi,

我正在编写一个报告,它需要来自两个不同位置的数据,一个是SQL Server数据库,另一个是DB2数据库,我用下面的代码完成了这项工作

这是我的SQL Server数据库:

private List<MerchantTerminal> GetListOfActiveTerminals(Int64 corebankingRecord, Int64 terminalRecord, bool dialup, bool ethernet, bool cellular, bool wifi, bool merchantAdviceBypass, bool merchantRefundBypass, bool authAdviceOnly)
{
    StringBuilder sql = new StringBuilder();

    sql.Append("Select distinct ");
    sql.Append("  POSH5_Prod_MerchantTerminalDetails.id ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.merchantRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.terminalID ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.TerminalRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.MCCRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.PINPadRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.terminalRentalFee ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.terminalRentalFeeCurrencyRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.DialUp ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.Ethernet ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.WiFi ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.GPRS ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.Internet ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.PrimaryCurrencyRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.SecondaryCurrencyRecord ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.TIP ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.AllowManuallyKeyedTransactions ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.MinimumTransactionVolume ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.MinimumTransactionVolumeCurrencyRecordID ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.MinimumTransactionVolumeFee ");
    sql.Append(", POSH5_Prod_MerchantTerminalDetails.MinimumTransactionVolumeFeeCurrencyRecordID ");
    sql.Append(", POSH5_Prod_MerchantDetails.bypassAdviceVerification ");
    sql.Append(", POSH5_Prod_MerchantDetails.bypassCreditVerification ");
    sql.Append(", POSH5_Prod_MerchantDetails.expireBypassCreditDate ");
    sql.Append("from POSH5_Prod_MerchantTerminalDetails ");
    sql.Append("left join  POSH5_Prod_MerchantDetails on POSH5_Prod_MerchantTerminalDetails.merchantRecord = POSH5_Prod_MerchantDetails.id ");
    sql.Append("where POSH5_Prod_MerchantTerminalDetails.active=@active ");
    sql.Append("and POSH5_Prod_MerchantDetails.corebankingRecord=@corebankingRecord ");
    //if (merchantAdviceBypass == true)
    //{
    //    sql.Append("and POSH5_Prod_MerchantDetails.bypassAdviceVerification=@merchantadvicebypass ");
    //}
    //else
    //{
    //    sql.Append("and POSH5_Prod_MerchantDetails.bypassAdviceVerification = 1 OR POSH5_Prod_MerchantDetails.bypassAdviceVerification = 0 ");
    //}
    //if (merchantRefundBypass == true)
    //{
    //    sql.Append("and POSH5_Prod_MerchantDetails.bypassCreditVerification=@merchantrefundbypass ");
    //}
    //else
    //{
    //    sql.Append("and POSH5_Prod_MerchantDetails.bypassCreditVerification = 1 OR POSH5_Prod_MerchantDetails.bypassCreditVerification = 0 ");
    //}


    if (terminalRecord > 0)
    {
        sql.Append("and terminalRecord=@terminalRecord ");
    }

    sql.Append("AND (");

    bool addedCommMethod = false;
    if (dialup)
    {
        sql.Append("POSH5_Prod_MerchantTerminalDetails.DialUp=1 ");
        addedCommMethod = true;
    }

    if (ethernet)
    {
        if (addedCommMethod)
        {
            sql.Append("OR ");
        }
        sql.Append("POSH5_Prod_MerchantTerminalDetails.Ethernet=1 ");
        addedCommMethod = true;
    }

    if (cellular)
    {
        if (addedCommMethod)
        {
            sql.Append("OR ");
        }

        sql.Append("POSH5_Prod_MerchantTerminalDetails.GPRS=1 ");
        addedCommMethod = true;
    }

    if (wifi)
    {
        if (addedCommMethod)
        {
            sql.Append("OR ");
        }

        sql.Append("POSH5_Prod_MerchantTerminalDetails.WiFi=1 ");
        addedCommMethod = true;
    }

    sql.Append(") ");

    sql.Append("order by terminalID; ");

    var merchantTerminalRecordList = new List<MerchantTerminal>();

    var serialnumberlist = PopulateSerialNumberList();

    using (SqlConnection connectionMSW = new SqlConnection(_connectionString))
    {
        connectionMSW.Open();

        SqlCommand commandMSW = new SqlCommand();
        commandMSW.CommandTimeout = 600;

        commandMSW.CommandText = sql.ToString();
        commandMSW.Connection = connectionMSW;

        commandMSW.Parameters.AddWithValue("@terminalRecord", terminalRecord);
        commandMSW.Parameters.AddWithValue("@active", true);
        commandMSW.Parameters.AddWithValue("@corebankingRecord", corebankingRecord);
        commandMSW.Parameters.AddWithValue("@merchantadvicebypass", merchantAdviceBypass);
        commandMSW.Parameters.AddWithValue("@merchantrefundbypass", merchantRefundBypass);

        using (SqlDataReader reader = commandMSW.ExecuteReader())
        {
            while (reader.Read())
            {
                merchantTerminalRecordList.Add(PopulateMerchantTerminalRecord(reader, serialnumberlist));
            }
        }
    }

    return merchantTerminalRecordList;
}
private POSHData PopulateSerialNumberList()
{
    POSHData result = new POSHData();

    List<POSHSerialNumber> serialResults = new List<POSHSerialNumber>();
    

    StringBuilder sql = new StringBuilder();
   
    sql.Append("select distinct termcert.termid, termcert.termserno, termcert.PPADSERNO, termcert.appname, termcert.appversion, terminal.TERMTYPE, terminal.PINPADID, terminal.LASTTRAN, terminal.EDCCRSRC, termcfg.tranauthonly, termcfg.tranadjust from posh.termcert as termcert LEFT JOIN posh.terminal as terminal ON termcert.termid = terminal.termid LEFT JOIN posh.termcfg as termcfg ON termcert.termid = termcfg.termid");

    DataSet dsResult = new DataSet();

    using (DB2Connection connectionPOSH = new DB2Connection(_connectionStringPOSH))
    {
        connectionPOSH.Open();

        DB2Command commandMSW = new DB2Command();
        commandMSW.CommandTimeout = 600;

        commandMSW.CommandText = sql.ToString();
        commandMSW.Connection = connectionPOSH;

        DB2DataAdapter adapter = new DB2DataAdapter();
        adapter.SelectCommand = commandMSW;
        adapter.Fill(dsResult);
    }

    foreach (DataRow item in dsResult.Tables[0].Rows)
    {
        POSHSerialNumber found = new POSHSerialNumber();

        found.termid = item["termid"].ToString().Trim();
        found.terminalSerialNumber = item["termserno"].ToString().Trim();
        found.pinPadSerialNumber = item["PPADSERNO"].ToString().Trim();
        found.appName = item["appname"].ToString().Trim();
        found.appVersion = item["appversion"].ToString().Trim();
        found.terminalRecord = dataTypeConversion.ToInt64(item["TERMTYPE"].ToString().Trim());
        var pinPadRecord = dataTypeConversion.ToInt64(item["PINPADID"].ToString().Trim());
        if (pinPadRecord > 0)
        {
            found.pinPadRecord = pinPadRecord;
            found.pinPadSerialNumber = item["PPADSERNO"].ToString().Trim();
        }
        var LastTransaction = dataTypeConversion.ToDouble(item["LASTTRAN"].ToString());
        found.LastTransaction = commonController.UnixTimeStampToDateTime(LastTransaction);

        found.SettlementType = item["EDCCRSRC"].ToString().Trim();

        found.tranAuthOnly = item["tranauthonly"].ToString().Trim();
        found.tranAdjust = item["tranadjust"].ToString().Trim();

        serialResults.Add(found);
    }


    result.poshSerialNumbers = serialResults;

    return result;
}
在只有500-1000条记录的开发和质量保证环境中,这似乎很好。在我的PROD环境中,它的速度要慢得多,因为我们要处理多达20k+的记录。目前在prod中提取此数据的最快方法是什么?它最多需要5-8分钟

谢谢你的帮助


编辑:在各自的数据库中运行我的查询后,看起来实际的速度减慢是在我使用的LINQ查询中,我想更好的问题是对于大量的数据,如何优化我的LINQ?

我不认为在MS SQL部分,至少在您显示的部分,您读取数据的方式有任何基本错误。现在使用ORM是很常见的(简洁、实体框架),但它们不是必需的

拉取此数据的最快方法是查找速度较慢的内容

在db客户端(例如SQL Management Studio)中运行查询

如果速度慢,请修复SQL

  • 例如,该表可能缺少索引
  • 数据库可能因为其他查询而忙
如果快速,检查如何调用代码

  • 添加带有计时的日志(围绕重要部分(例如,围绕使用)的
    ),以便准确知道哪个部分速度慢。这可能不是数据库调用

当您添加
POSHSerialNumber
对象时,您需要执行
found.termid=item[“termid”].ToString().Trim();
,因此在使用
Find
时无需再次执行此操作,可能与
MerchantTerminal
相同,您可以避免使用
Trim
这两种方法来构建查询!您可以对主节使用逐字字符串,使其更具可读性。和
string.Join(…,,,,,,,,,)或
会很有用。想到的事情:1.考虑你需要哪些列和不需要哪些列2.合理地编制索引,特别是
POSH5\u Prod\u merchantdetdetails
使用
包含
列,因为它只是几个列3.不要使用
独立的
,如果你不需要的话,考虑连接的作用4.不要使用
顺序通过
,进行客户端排序。5.
优先于
,因此使用括号
()
6.左连接没有任何意义,因为您稍后会在……….的一列上进行筛选。要么在
上的
中进行筛选,要么更改为
内部连接
7。
通常会影响性能,因为索引8很难使用。
private void GetSerialNumber(POSHData poshData, MerchantTerminal foundTerminal)
{
    var result = poshData.poshSerialNumbers.Find(x => x.termid.Trim() == foundTerminal.terminalID.Trim());


    if (result != null)
    {
        foundTerminal.terminalSerialNumber = result.terminalSerialNumber;
        foundTerminal.pinPadSerialNumber = result.pinPadSerialNumber;
        foundTerminal.appName = result.appName;
        foundTerminal.appVersion = result.appVersion;
        foundTerminal.pINPadRecord = result.pinPadRecord;
        foundTerminal.terminalRecord = result.terminalRecord;
        foundTerminal.LastTransactionDateTime = result.LastTransaction;

        if (foundTerminal.pinPadSerialNumber.Length == 0)
        {
            foundTerminal.pinPadSerialNumber = result.pinPadSerialNumber;
        }

        switch (result.SettlementType)
        {
            case "2":
                foundTerminal.PABX = "Journal";
                break;
            case "3":
                foundTerminal.PABX = "Batch Close Required";
                break;
            default:
                foundTerminal.PABX = "Unknown";
                break;
        }
        foundTerminal.AdviceText = result.tranAdjust;
        foundTerminal.AuthOnly = result.tranAuthOnly;
    }