0Pricing
C# Academy · บทเรียน

คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ

เพิ่มประสิทธิภาพคำสั่งสืบค้นด้วย EF.CompileQuery, AsNoTracking และการฉายข้อมูลด้วย Select

คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

การคอมไพล์คิวรีของ EF Core

ทุกครั้งที่ EF Core เรียกใช้คิวรี LINQ จะต้องแยกวิเคราะห์ต้นไม้นิพจน์ แปลงเป็น SQL และตรวจสอบความถูกต้อง สำหรับเส้นทางการทำงานที่เรียกใช้บ่อย ค่าใช้จ่ายส่วนนี้จะสะสมเพิ่มขึ้น EF Core จึงมีเครื่องมือหลายอย่างเพื่อลดค่าใช้จ่ายดังกล่าว

AsNoTracking สำหรับคิวรีแบบอ่านอย่างเดียว

AsNoTracking() จะข้ามการลงทะเบียนกับตัวติดตามการเปลี่ยนแปลง สำหรับคิวรีแบบอ่านอย่างเดียว เช่น การตอบกลับ API และรายงาน วิธีนี้เป็นการปรับปรุงที่ทำได้ง่ายและให้ผลมากที่สุด โดยทั่วไปจะเร็วขึ้น 2–5 เท่าและใช้หน่วยความจำน้อยลง

// With tracking (default) — for entities you'll modify
var tracked = await _db.Products.FirstOrDefaultAsync(p => p.Id == 1);

// Without tracking — for read-only
var dto = await _db.Products
    .AsNoTracking()
    .Where(p => p.IsActive)
    .Select(p => new ProductDto { Id = p.Id, Name = p.Name })
    .ToListAsync();

คิวรีที่คอมไพล์ไว้

EF.CompileAsyncQuery จะคอมไพล์คิวรี LINQ ล่วงหน้าเป็นผู้รับมอบหมาย การแปลจะเกิดขึ้นครั้งเดียวเมื่อเริ่มต้นระบบ ส่วนการเรียกใช้ครั้งต่อ ๆ ไปจะข้ามขั้นตอนการคอมไพล์ทั้งหมด

// Define once, reuse many times
private static readonly Func<AppDbContext, int, Task<Product?>> GetProductById =
    EF.CompileAsyncQuery(
        (AppDbContext db, int id) =>
            db.Products.AsNoTracking().FirstOrDefault(p => p.Id == id));

// Usage
var product = await GetProductById(_db, 42);

การเลือกเฉพาะข้อมูลด้วย Select เพื่อประสิทธิภาพ

ควรเลือกเฉพาะฟิลด์ที่ต้องการใช้อย่างแท้จริงเสมอ การเลือกออบเจ็กต์ถ่ายโอนข้อมูลแทนเอนทิตีทั้งหมดจะลดจำนวนคอลัมน์ที่ดึง ข้อมูลที่ส่งผ่านเครือข่าย และแรงกดดันต่อ GC

// Load entire entity (over-fetch)
var all = await _db.Products.ToListAsync();

// Projection: only fetch needed columns
var names = await _db.Products
    .AsNoTracking()
    .Select(p => new { p.Id, p.Name, p.Price })
    .ToListAsync();
// SQL: SELECT Id, Name, Price FROM Products

คำแนะนำดัชนีและการปรับคิวรีดิบให้เหมาะสม

EF Core จะใช้ดัชนีฐานข้อมูลที่คุณกำหนดค่าด้วย HasIndex() ดัชนีหลายคอลัมน์ ดัชนีแบบกรองข้อมูล และคอลัมน์ที่รวมไว้ ล้วนส่งผลต่อประสิทธิภาพของแผนการคิวรี

// Configure compound index in OnModelCreating
modelBuilder.Entity<Order>()
    .HasIndex(o => new { o.CustomerId, o.Status })
    .HasFilter("[Status] = 0")  // filtered index
    .IncludeProperties(o => o.PlacedAt);

// The query below will use this index efficiently
var pending = await _db.Orders
    .AsNoTracking()
    .Where(o => o.CustomerId == 5 && o.Status == OrderStatus.Pending)
    .ToListAsync();

การแบ่งหน้าด้วย Skip และ Take

ควรแบ่งหน้าชุดผลลัพธ์ขนาดใหญ่เสมอ Skip และ Take จะแปลเป็น SQL OFFSET/FETCH ทำให้ไม่ต้องโหลดแถวหลายพันแถวไว้ในหน่วยความจำ

int page = 2, pageSize = 25;

var products = await _db.Products
    .AsNoTracking()
    .Where(p => p.IsActive)
    .OrderBy(p => p.Name)
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();
// SQL: ... ORDER BY Name OFFSET 25 ROWS FETCH NEXT 25 ROWS ONLY

การนับอย่างมีประสิทธิภาพ

ใช้ CountAsync() หรือ AnyAsync() แทนการโหลดระเบียนเพียงเพื่อจะนับจำนวน AnyAsync() ยังเร็วกว่า COUNT เมื่อคุณต้องการตรวจสอบเพียงว่ามีข้อมูลอยู่หรือไม่

// Total count for pagination
int totalCount = await _db.Products
    .Where(p => p.IsActive)
    .CountAsync();

// Existence check — faster than Count > 0
bool hasExpensive = await _db.Products
    .AnyAsync(p => p.Price > 1000m);
// SQL: IF EXISTS (SELECT 1 FROM ...) SELECT 1

การแทรกข้อมูลจำนวนมากด้วย AddRange

ใช้ AddRange เพื่อเพิ่มเอนทิตีหลายรายการพร้อมกัน EF Core จะรวมคำสั่ง INSERT หลายรายการเป็นชุดเพื่อลดจำนวนการไปกลับระหว่างแอปกับฐานข้อมูล โดยควบคุมด้วย MaxBatchSize ของผู้ให้บริการ

var newProducts = Enumerable.Range(1, 1000)
    .Select(i => new Product { Name = $"Product {i}", Price = i * 1.5m })
    .ToList();

_db.Products.AddRange(newProducts);
await _db.SaveChangesAsync();
// Batched: typically 100-1000 rows per round-trip

EF.Functions สำหรับฟังก์ชันฐานข้อมูล

EF.Functions แสดงฟังก์ชันเฉพาะของฐานข้อมูล เช่น LIKE ส่วนของวันที่ และการค้นหาข้อความเต็ม ซึ่ง EF Core จะแปลเป็น SQL แทนการประมวลผลในหน่วยความจำ

// LIKE pattern search (SQL-side)
var results = await _db.Products
    .Where(p => EF.Functions.Like(p.Name, "%keyboard%"))
    .AsNoTracking()
    .ToListAsync();

// Date difference (SQL-side)
var recentOrders = await _db.Orders
    .Where(o => EF.Functions.DateDiffDay(o.PlacedAt, DateTime.UtcNow) <= 7)
    .ToListAsync();

การวินิจฉัยคิวรีที่ทำงานช้า

เปิดการบันทึกคิวรีของ EF Core เพื่อดู SQL ที่สร้างขึ้น ใช้ EnableSensitiveDataLogging() ในสภาพแวดล้อมการพัฒนาเพื่อดูค่าพารามิเตอร์

builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlServer(connStr)
       .LogTo(Console.WriteLine, LogLevel.Information)
       .EnableSensitiveDataLogging() // dev only!
       .EnableDetailedErrors());     // dev only!

ในสถานการณ์จริง: ปลายทางรายการที่ปรับให้เหมาะสม

ปลายทางรายการที่พร้อมใช้งานจริงจะรวม AsNoTracking การเลือกเฉพาะข้อมูล ดัชนี และการแบ่งหน้าเข้าด้วยกัน เพื่อให้ได้ประสิทธิภาพสูงสุด

app.MapGet("/products", async (
    AppDbContext db,
    string? search,
    int page = 1, int size = 20) =>
{
    var query = db.Products
        .AsNoTracking()
        .Where(p => p.IsActive);

    if (!string.IsNullOrEmpty(search))
        query = query.Where(p => EF.Functions.Like(p.Name, $"%{search}%"));

    var total = await query.CountAsync();
    var items = await query
        .OrderBy(p => p.Name)
        .Skip((page - 1) * size).Take(size)
        .Select(p => new { p.Id, p.Name, p.Price })
        .ToListAsync();

    return Results.Ok(new { total, items });
});

ตรวจสอบความเข้าใจ

ประโยชน์หลักของ EF.CompileAsyncQuery เมื่อเทียบกับคิวรี LINQ ทั่วไปคืออะไร

สรุป: คิวรีที่คอมไพล์ไว้และประสิทธิภาพ

ประเด็นสำคัญ:

  • AsNoTracking(): ข้ามตัวติดตามการเปลี่ยนแปลงสำหรับการอ่านอย่างเดียว เป็นการปรับปรุงที่ทำได้ง่ายและเร็วที่สุด
  • EF.CompileAsyncQuery: คอมไพล์คิวรีที่เรียกใช้บ่อยล่วงหน้าเป็นผู้รับมอบหมาย
  • การเลือกเฉพาะข้อมูลด้วย Select: ดึงเฉพาะคอลัมน์ที่จำเป็น
  • ดัชนีที่เหมาะสม (HasIndex) ช่วยปรับปรุงแผนการคิวรีได้อย่างมาก
  • แบ่งหน้าด้วย Skip/Take และใช้ AnyAsync เพื่อตรวจสอบว่ามีข้อมูลอยู่หรือไม่
  • เปิดการบันทึกคิวรีในสภาพแวดล้อมการพัฒนาเพื่อค้นหา SQL ที่ทำงานช้าหรือไม่เป็นไปตามคาด

คำถามที่พบบ่อย

บทเรียน “คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ”

เพิ่มประสิทธิภาพคำสั่งสืบค้นด้วย EF.CompileQuery, AsNoTracking และการฉายข้อมูลด้วย Select คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง
  2. SQL ดิบ โพรซีเยอร์ที่จัดเก็บ และการแทรกค่า
  3. คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ
  4. ตัวกรองคำสั่งสืบค้นส่วนกลางและเอนทิตีที่เป็นเจ้าของ
← กลับไปที่ C# Academy