Fork me on GitHub

[转载]我们这样做报表之蚂蚁战术

常有同学问起,XCode能够通过分表分库做海量数据CURD,统计报表怎么做?
其实这个超级简单!!!
很多人习惯了用group by,很慢,非常慢,并且不适用于XCode的分表分库。
那么,我们新生命团队是怎么做的呢?
我们有一个类似于蚂蚁搬家的蚂蚁战术,根本不在乎有多少数据,不在乎如何分表分库!

public static void ProcessAll(Int32 year, Int32 month)
{
    if (month < 0)
    {
        for (int i = 0; i < 13; i++)
        {
            ProcessAll(year, i);
        }
        return;
    }

    var list = new List<Int32>();
    foreach (var item in AdminHelper.Factory.Cache.Entities)
    {
        var id = (Int32)item["ID"];
        if (!list.Contains(id)) list.Add(id);
    }

    Process(list.ToArray(), year, month);

    // 统计全部
    Process(null, year, month);
}

public static void Process(Int32 id, Int32 year, Int32 month)
{
    if (id <= 0) throw new ArgumentNullException("salesmanid");

    Process(new Int32[] { id }, year, month);
}

public static void Process(Int32[] ids, Int32 year, Int32 month)
{
    if (year < 0) throw new ArgumentNullException("year");
    if (month < 0) throw new ArgumentNullException("month");

    // 找出来哪个没有的
    var ds = new List<Int32>();
    if (ids != null && ids.Length > 0) ds.AddRange(ids);
    var istotal = ds.Count > 0;

    var list = SalesOrder.SearchStatistics(ids, year, month, SalesOrder._.SalesmanID);
    if (list.Count < 1) return;
    
    using (var trans = Meta.CreateTrans())
    {
        foreach (var sd in list)
        {
            // 跳过无数据记录
            if (sd.Status < 1) continue;

            // 找出来哪个没有的
            if (ds.Contains(sd.SalesmanID)) ds.Remove(sd.SalesmanID);

            var cs = FindBySalesmanIDAndYearAndMonth(sd.SalesmanID, year, month);
            if (cs == null)
            {
                cs = new SalesmanStatistics();
                cs.SalesmanID = sd.SalesmanID;
                cs.Year = year;
                cs.Month = month;
            }

            // 验证销售员
            if (!istotal)
            {
                var man = AdminHelper.FindByID(sd.SalesmanID);
                if (man != null) cs.Name = man.FriendName;
            }
            else
                cs.Name = "【所有】";

            cs.Count = sd.Status;
            cs.Cost = sd.Cost;
            cs.Profit = sd.Profit;
            cs.PushMoney = sd.PushMoney;
            cs.LastID = sd.ID;
            cs.LastTime = sd.CreateTime;

            cs.Save();
        }

        // 删除多余的
        if (ds.Count > 0)
        {
            FindAll(_.SalesmanID.In(ds) & _.Year == year & _.Month == month, null, null, 0, 0).Delete();
        }

        // 再查一次新客户
        //exp &= SalesOrder._.IsNewCustomer == true;
        list = SalesOrder.SearchStatistics(ids, year, month, SalesOrder._.SalesmanID, true);
        if (list.Count > 0)
        {
            foreach (var sd in list)
            {
                // 跳过无数据记录
                if (sd.Status < 1) continue;

                var cs = FindBySalesmanIDAndYearAndMonth(sd.SalesmanID, year, month);
                if (cs == null)
                {
                    cs = new SalesmanStatistics();
                    cs.SalesmanID = sd.SalesmanID;
                    cs.Year = year;
                    cs.Month = month;
                }

                cs.NewCount = sd.Status;
                cs.NewCost = sd.Cost;
                cs.NewProfit = sd.Profit;
                cs.NewPushMoney = sd.PushMoney;

                cs.Save();
            }
        }

        trans.Commit();
    }
}

上面是统计某个月所有销售员业绩的代码,计算以后就可以得到月度销售报表!
实际上,我们可以在用户查询数据或者查看月度报表的时候,开一个后台线程,默默的去执行这些统计函数。

这些函数的最大特点就是,逐步取出来数据,然后一个个实体对象累加,最后保存到统计表里面去!
用户查看统计报表的时候,实际上是直接从统计表里面拿数据。

有同学要问,这样岂不是拿不到最新的数据?
哦,恐怕是的!但是,你会在乎那么几秒钟的实时性吗?当你发现数据不够新的时候,也许等2秒钟后再点一次页面,已经是最新的了!

最最最重要的是:
蚂蚁战术,非常容易写,会C#就行,不用复杂SQL,不用存储过程。还可以跨表跨库跨服务器,还可以跨不同数据库类型……

End.

PS:这篇文章很好,Mark,感谢石头哥!

原文:http://www.newlifex.com/showtopic-1136.aspx

posted @ 2014-06-09 18:05  VAllen  阅读(605)  评论(1编辑  收藏  举报