วิธีแก้ปัญหาที่จำเป็นสำหรับการดำเนินการ GroupBy ของ EF Core ในหน่วยความจำแทนใน SQL

ฉันกำลังทำงานใน Entity Framework Core 1.1.0 (และการอัปเกรดไม่ใช่ตัวเลือกในตอนนี้ เนื่องจากการเปลี่ยนแปลงที่ไม่สมบูรณ์ในเวอร์ชันที่ใหม่กว่า) คำถามของฉันอยู่ในรูปแบบต่อไปนี้:

var q = db.MyTable
            .GroupBy(t => new { t.Field1 })
            .Select(g => new
            {
                g.Key.Field1,
                MaxField2 = g.Max(x => x.Field2)
            })
            .ToList();

ในโค้ดทดสอบสิ่งนี้ทำงานได้ดีและส่งคืนข้อมูลที่คาดหวัง แต่เมื่อปรับใช้ในสภาพแวดล้อมจริงด้วยข้อมูลจริง ระบบจะหมดเวลา ทำไม ฉันลองดมกลิ่นบนเซิร์ฟเวอร์ SQL และนี่คือ SQL จริง:

SELECT [t].[Field1], [t].[Field2], [t].[Field3], [t].[Field4], [t].[Field5]
FROM [dbo].[MyTable] AS [t]
ORDER BY [t].[Field1]

โอ้. นั่นสิจะอธิบายได้ EF รวบรวมเฉพาะแบบสอบถามจนถึง .GroupBy() ลงใน SQL ดังนั้นพยายามโหลดเนื้อหา ทั้งหมด ของตาราง (ประมาณ 17 ล้านบันทึกในขณะที่เขียนนี้) ลงในหน่วยความจำ และส่วนที่เหลือของการจัดกลุ่ม และการสั่งซื้อควรจะทำในความทรงจำ

ข้อเสนอแนะใด ๆ เกี่ยวกับวิธีการแก้ไขแบบสอบถามนี้เพื่อให้การยกของหนักเสร็จสิ้นใน SQL


person Shaul Behr    schedule 19.07.2017    source แหล่งที่มา
comment
ทำไมคุณไม่ทำให้ข้อความค้นหาของคุณอ่านง่ายขึ้นอีกเล็กน้อยเพื่อหลีกเลี่ยงข้อยกเว้น ใช้ตัวแปร Expression<Func<>> และทำงานกับตัวแปรเหล่านั้น ฉันไม่คิดว่าจะมีใครต้องการสร้างโครงสร้าง DB ของคุณใหม่ตั้งแต่ต้น ทำงานร่วมกับ EF Core เวอร์ชันเก่า และแก้ไขข้อบกพร่องนี้ให้กับคุณโดยสมบูรณ์   -  person Matthias Burger    schedule 19.07.2017
comment
@MatthiasBurger ดูการอัปเดตของฉัน   -  person Shaul Behr    schedule 19.07.2017
comment
@ShaulBehr คุณได้ทดสอบแบบสอบถามที่ลดลงนี้แล้วหรือยัง? มันแสดงให้เห็นปัญหาเดียวกันหรือไม่?   -  person xanatos    schedule 19.07.2017
comment
@xanatos ใช่ ฉันได้ทดสอบแบบสอบถามแบบลดขนาดแล้ว พฤติกรรมเดียวกัน   -  person Shaul Behr    schedule 19.07.2017
comment
หากคุณต้องการคำสั่งดังกล่าว EF Core คือความผิดพลาดครั้งใหญ่ที่สุดที่คุณทำ :( ไม่มีวิธีแก้ปัญหา ไม่ว่าคุณจะพยายามสร้างข้อยกเว้นหรือดำเนินการในหน่วยความจำ และไม่มีการสนับสนุนแบบสอบถาม SQL โดยพลการ   -  person Ivan Stoev    schedule 19.07.2017
comment
@IvanStoev ไม่ถูกต้องทั้งหมด ฉันพบวิธีแก้ไขแล้ว ดูคำตอบของฉัน   -  person Shaul Behr    schedule 19.07.2017
comment
ดีสำหรับคุณ! จนกว่าคุณจะต้องการผลรวมอื่นเช่น Sum :)   -  person Ivan Stoev    schedule 19.07.2017
comment
@IvanStoev (สับเท้าอย่างเชื่องช้า) อืม... ก็... 8-\   -  person Shaul Behr    schedule 19.07.2017


คำตอบ (3)


ตามที่ @xanatos ชี้ให้เห็น สิ่งนี้ไม่รองรับใน EF Core 1.1.0 (และไม่ใช่ด้วยซ้ำ 2.0.0) อย่างไรก็ตาม มีวิธีแก้ไขชั่วคราวโดยใช้ SQL ตามตัวอักษร:

var q = db.MyTable
        .FromSql("select t.* from " +
                 "  (select distinct Field1 from MyTable) t0 " +
                 "cross apply " +
                 "  (select top 1 t.* from MyTable t " +
                 "  where t.Field1 = t0.Field1 " +
                 "  order by t.Field2 desc) t")                     
        .Select(t => new
        {
            t.Field1,
            MaxField2 = t.Field2
        })
        .ToList();

ไม่ใช่วิธีแก้ปัญหาที่ฉันหวังไว้ แต่มันก็ใช้ได้ผลดี

person Shaul Behr    schedule 19.07.2017

ไม่รองรับ EF Core 1.1.0: https://github.com/aspnet/EntityFramework/issues/2341

บางครั้งตัวดำเนินการ GroupBy() ของ LINQ สามารถแปลเป็น GROUP BY clause ของ SQL ได้ โดยเฉพาะอย่างยิ่งเมื่อมีการใช้ฟังก์ชันรวมในการฉายภาพ

น่าเสียดายที่ระบบไม่รองรับแม้แต่ใน EF Core 2.0.0

person xanatos    schedule 19.07.2017
comment
หากต้องการทราบรายการที่สมบูรณ์ยิ่งขึ้นว่ามีอะไรบ้างที่มีอยู่แล้วหรือไม่ ลองดูที่ลิงค์นี้ docs.microsoft.com/en-us/ef/efcore- และ-ef6/คุณลักษณะ - person Jordy van Eijk; 19.07.2017

ดังที่คุณเห็นในรายการบล็อก นี้ GROUP BY จะเป็น รองรับใน 2.1 ซึ่งยังไม่เปิดตัว แต่ คาดว่าจะเกิดขึ้นในไตรมาสที่ 1-ไตรมาสที่ 2 ปี 2018 ไตรมาสที่ 4 ปี 2017

person JotaBe    schedule 06.09.2017
comment
ดูเหมือนว่าพวกเขาจะเลื่อนการเปิดตัว 2.1 ไปเป็น Q1-Q2 2018 :( - person ThunderDev; 13.11.2017