Beberapa informasi dasar tentang arsitektur saya:

  • C# Web API di .Net 4.8
  • Kerangka Entitas 6.2
  • database Oracle

Kasus uji: perbarui tentang 17 record dalam tabel yang terdiri dari 1.126.126 record. Tabel memiliki kunci utama pada kolom Id.

Opsi 1: (Waktu eksekusi ~43 detik)

var items = _context.TRADELINEs.AsNoTracking()
                    .Where(x => tradelines.Keys.ToList().Contains(x.ID))
                    .ToList();            

foreach(var i in tradelines) // tradelines is -> Dictionary<string,string> tradelines
{                
    string consolidateFlag = string.IsNullOrEmpty(i.Value) ? "0" : i.Value;
    var newTradeline = new TRADELINE
    {
        ID = i.Key,
        PREVCONSOLFLG = items.Where(x => x.ID == i.Key).FirstOrDefault().CONSOLFLG,
        MODTS = DateTime.Now,
        CONSOLFLG = consolidateFlag
    };
    _context.TRADELINEs.Attach(newTradeline);

    _context.Entry(newTradeline).Property(x => x.PREVCONSOLFLG).IsModified = true;
    _context.Entry(newTradeline).Property(x => x.CONSOLFLG).IsModified = true;
    _context.Entry(newTradeline).Property(x => x.MODTS).IsModified = true;
}
_context.SaveChanges();

Opsi 2: (Waktu eksekusi ~36 detik)

_context.Configuration.AutoDetectChangesEnabled = false;
var items = _context.TRADELINEs.AsNoTracking()
                    .Where(x => tradelines.Keys.ToList().Contains(x.ID))
                    .ToList();            

foreach(var i in tradelines) // tradelines is -> Dictionary<string,string> tradelines
{                
    string consolidateFlag = string.IsNullOrEmpty(i.Value) ? "0" : i.Value;
    var newTradeline = new TRADELINE
        {
            ID = i.Key,
            PREVCONSOLFLG = items.Where(x => x.ID == i.Key).FirstOrDefault().CONSOLFLG,
            MODTS = DateTime.Now,
            CONSOLFLG = consolidateFlag
        };

    _context.TRADELINEs.Attach(newTradeline);
    _context.Entry(newTradeline).Property(x => x.PREVCONSOLFLG).IsModified = true;
    _context.Entry(newTradeline).Property(x => x.CONSOLFLG).IsModified = true;
    _context.Entry(newTradeline).Property(x => x.MODTS).IsModified = true;
}

_context.SaveChanges();
_context.Configuration.AutoDetectChangesEnabled = true;

Saya menambahkan

_context.Database.Log = s => System.Diagnostics.Debug.WriteLine("SQL : " + s);

Baris untuk memverifikasi SQL yang dihasilkan. Dalam log saya dapat melihat bahwa setiap pernyataan pembaruan memakan waktu sekitar 2-3 detik tetapi pernyataan SQL yang sama dijalankan dalam beberapa milidetik di alat Pengembang SQL.

Pertanyaan: Apakah ada cara untuk membuat eksekusi lebih cepat saat menggunakan Entity Framework saja? Saya ingin mempertahankan ExecuteSqlCommand sebagai opsi terakhir.

Berikut adalah SQL yang dihasilkan oleh EF:

SQL : update "TRADELINE"
set "CONSOLFLG" = :p0, "MODTS" = :p1, "PREVCONSOLFLG" = :p2
where ("ID" = :p3)

SQL : -- :p0: '0' (Type = String, Size = 1)

SQL : -- :p1: '12/13/2019 12:09:36 PM' (Type = Date)

SQL : -- :p2: '0' (Type = String, Size = 1)

SQL : -- :p3: 'b0b2a534-db52-4dcc-b369-a5f222157d7c' (Type = String, Size = 36)

SQL : -- Executing at 12/13/2019 12:10:01 PM -06:00

SQL : -- Completed in 2538 ms with result: 1
1
Shaggy 13 Desember 2019, 23:35

1 menjawab

Jawaban Terbaik

Itu terkait dengan Parameter sniffing. Mengikuti dua jawaban posting membantu saya menemukan solusi:

https://stackoverflow.com/a/21841170/1169180

https://stackoverflow.com/a/15772873/1169180

Saya harus mengubah model saya menjadi:

public partial class TRADELINE
    {
        [StringLength(36)]
        [Column(TypeName = "char")] // This line got added later
        public string ID { get; set; }
    }

Setelah melakukan perubahan ini, setiap kueri pembaruan saya membutuhkan waktu sekitar ~50 ms untuk diproses.

1
Shaggy 14 Desember 2019, 00:04