Solusi diperlukan agar EF Core melakukan operasi GroupBy di memori, bukan di SQL

Saya bekerja di Entity Framework Core 1.1.0 (dan pemutakhiran bukanlah suatu pilihan saat ini, karena perubahan yang dapat menyebabkan gangguan pada versi yang lebih baru). Permintaan saya adalah dalam bentuk berikut:

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

Dalam kode pengujian ini berfungsi dengan baik dan mengembalikan data yang diharapkan. Namun ketika diterapkan ke lingkungan nyata, dengan data nyata, waktu habisnya. Mengapa? Baiklah, saya memasang sniffer di server SQL, dan inilah SQL sebenarnya:

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

Oh. Itu akan menjelaskannya. EF hanya mengkompilasi kueri hingga .GroupBy() ke dalam SQL, sehingga mencoba memuat keseluruhan konten tabel (sekitar 17 juta catatan saat penulisan ini) ke dalam memori, dan pengelompokan lainnya dan pemesanan seharusnya dilakukan dalam memori.

Adakah saran bagaimana cara mengerjakan ulang kueri ini sehingga pekerjaan berat selesai di SQL?


person Shaul Behr    schedule 19.07.2017    source sumber
comment
mengapa Anda tidak membuat kueri Anda lebih mudah dibaca untuk menghindari pengecualian? gunakan variabel Expression<Func<>> dan kerjakan dengannya. Saya rasa tidak ada orang yang ingin membangun kembali struktur DB Anda dari awal, bekerja dengan EF Core versi lama dan men-debug ini sepenuhnya untuk Anda.   -  person Matthias Burger    schedule 19.07.2017
comment
@MatthiasBurger lihat pembaruan saya.   -  person Shaul Behr    schedule 19.07.2017
comment
@ShaulBehr Sudahkah Anda menguji kueri yang dikurangi ini? Apakah ini menunjukkan masalah yang sama?   -  person xanatos    schedule 19.07.2017
comment
@xanatos, ya, saya telah menguji kueri yang dikurangi. Perilaku yang sama.   -  person Shaul Behr    schedule 19.07.2017
comment
Jika Anda memerlukan pertanyaan seperti itu, EF Core adalah kesalahan terbesar yang pernah Anda buat :( Tidak ada solusi, apa pun yang Anda coba akan menghasilkan pengecualian atau dijalankan di memori. Dan tidak ada permintaan SQL sewenang-wenang yang didukung.   -  person Ivan Stoev    schedule 19.07.2017
comment
@IvanStoev tidak sepenuhnya akurat. Saya menemukan solusi; lihat jawabanku.   -  person Shaul Behr    schedule 19.07.2017
comment
Bagus untukmu! Sampai Anda membutuhkan agregat lain seperti Sum :)   -  person Ivan Stoev    schedule 19.07.2017
comment
@IvanStoev (mengocok kaki dengan canggung) um... baiklah... 8-\   -  person Shaul Behr    schedule 19.07.2017


Jawaban (3)


Seperti yang ditunjukkan oleh @xanatos, ini tidak didukung di EF Core 1.1.0 (dan bahkan 2.0.0). Namun, ada solusinya, menggunakan SQL literal:

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();

Bukan solusi yang saya harapkan, namun hasilnya luar biasa.

person Shaul Behr    schedule 19.07.2017

Tidak didukung di EF Core 1.1.0: https://github.com/aspnet/EntityFramework/issues/2341

Operator GroupBy() LINQ terkadang dapat diterjemahkan ke klausa GROUP BY SQL, khususnya ketika fungsi agregat diterapkan dalam proyeksi.

Sayangnya ini tidak didukung bahkan di EF Core 2.0.0.

person xanatos    schedule 19.07.2017
comment
Untuk daftar lebih lengkap apa saja yang sudah ada atau belum. Lihatlah tautan ini. docs.microsoft.com/en-us/ef/efcore- dan-ef6/fitur - person Jordy van Eijk; 19.07.2017

Seperti yang Anda lihat di entri blog ini, GROUP BY akan menjadi didukung di versi 2.1, yang belum dirilis, namun direncanakan untuk Q1-Q2 2018 Q4 2017.

person JotaBe    schedule 06.09.2017
comment
Tampaknya mereka telah menunda rilis 2.1 ke Q1-Q2 2018 :( - person ThunderDev; 13.11.2017