4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

テーブル結合のLINQ(GroupJoin, SelectMany)と全データ取得後にプログラムで処理する速度の比較

Posted at

仕事でプログラミングやってた時に少し気になったので、実験してみた。

複数のテーブルを結合して一括でデータを取得するのと、各テーブルのデータを取得した後、プログラム側でデータを成型することのどっちが速いか。

1. 結論

EntityFrameworkで結合したほうが(かなり)早かった。

2. 環境

IDE:Visual Studio 2019
DB:Microsoft SQL Server 2017

3. やったこと

以下のような処理の速度を比較。

1つめ。テーブルからデータをガバっと取り、プログラム側で外部結合っぽい処理をする。

    class Program
    {
        static void Main(string[] args)
        {
            var context = new TestContext();
            var sw = new Stopwatch();

            var _studentReposiroty = new StudentsRepository(context);
            var _classReposiroty = new ClassesRepository(context);
            var _clabReposiroty = new ClabsRepository(context);
            var _userReposiroty = new UsersRepository(context);

            var viewList = new List<TestViewModel>();

            // プログラムでデータ成型
            sw.Start();

            // 特定の生徒データ取得
            var students = _studentReposiroty.List();

            // クラブとかのIdを取得
            var clabIds = students.Select(x => x.ClabId).ToList();
            var classIds = students.Select(x => x.ClassId).ToList();
            var userIds = students.Select(x => x.CreatedByUserId).ToList();

            // IDに紐づく名称のリストを(ID, Name)のタプルで取得
            var classes = _classReposiroty.ListNameById(classIds);
            var clabs = _clabReposiroty.ListNameById(clabIds);
            var users = _userReposiroty.ListNameById(userIds);

            // データ内にあるIDをNameに置き換える。対応するものがなかったら空文字。
            students.ForEach(r =>
            {
                var className = !string.IsNullOrEmpty(classes.Find(x => x.Item1.Equals(r.ClassId)).Item2) 
                    ? classes.Find(x => x.Item1.Equals(r.ClassId)).Item2 : string.Empty;

                var clabName = !string.IsNullOrEmpty(clabs.Find(x => x.Item1.Equals(r.ClabId)).Item2)
                    ? clabs.Find(x => x.Item1.Equals(r.ClabId)).Item2 : string.Empty;

                var userName = !string.IsNullOrEmpty(users.Find(x => x.Item1.Equals(r.CreatedByUserId)).Item2)
                    ? users.Find(x => x.Item1.Equals(r.CreatedByUserId)).Item2 : string.Empty;

                var testViewModel = new TestViewModel
                {
                    Id = r.Id,
                    Name = r.Name,
                    ClassName = className,
                    ClabName = clabName,
                    CreatedByUserName = userName,
                    Age = r.Age
                };

                viewList.Add(testViewModel);
            });

            sw.Stop();

            Console.WriteLine($"処理時間: {sw.ElapsedMilliseconds}ミリ秒");
            Console.WriteLine();

2つ目。LINQで一気にデータを取る。

            sw.Restart();

            var viewList2 = _studentReposiroty.GetTestViewModels();

            sw.Stop();
        public List<TestViewModel> GetTestViewModels()
        {
            var returnList = _testContext.Students.GroupJoin(
                _testContext.Classes, s => s.ClassId, c => c.Id,
                (s, c) => new
                {
                    s = s,
                    c = c
                }
            ).SelectMany(
                x => x.c.DefaultIfEmpty(),
                (s, c) => new { s = s.s, c }
                )

            .GroupJoin(_testContext.Clabs, sc => sc.s.ClabId, clab => clab.Id, (sc, clab) => new { sc, clab })
            .SelectMany(x => x.clab.DefaultIfEmpty(), (sc, clab) => new { sc = sc.sc, clab })
            .GroupJoin(_testContext.Users, scc => scc.sc.s.CreatedByUserId, u => u.Id, (scc, u) => new { scc, u })
            .SelectMany(x => x.u.DefaultIfEmpty(), (scc, u) => new TestViewModel
            {
                Id = scc.scc.sc.s.Id,
                Name = scc.scc.sc.s.Name,
                ClabName = scc.scc.clab.Name ?? string.Empty,
                ClassName = scc.scc.sc.c.Name ?? string.Empty,
                CreatedByUserName = u.Name ?? string.Empty,
                Age = scc.scc.sc.s.Age
            }).ToList();

            return returnList;
        }

4.測定結果

前者:4189ミリ秒
後者:160ミリ秒

というわけで、後者のほうが全然早かった。。。。
ListじゃなくてHashSet使うともっと違うのかしら。
でもまあ、ミリ秒の世界だったら、正直HashSetでもっと早くなったところでどっちでもいいかなぁ。。。。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?