模拟生产环境的数据分布来批量造测试数据(使用几何分布公式且不利用临时表)java实现

背景

需要模拟生产环境的数据分布来往测试数据批量插入数据,以做一些性能测试。一开始是在存储过程中使用临时表,即往临时表赋值符合几何分布规律的插入数量,然后遍历该临时表来insert。后面发现这种情况只能满足一个字段的分布,要想满足其它字段的数据分布,只能用另一个临时表来为已经插入的数据进行update。这样感觉很麻烦,所以就想有没有不依赖临时表的实现。

前提知识

几何分布(Geometric Distribution)的公式:

几何分布的分布图:

本站关于几何分布的学习笔记(个人觉得还可以):概率论的学习和整理8: 几何分布-CSDN博客

代码

版本一:未进行一定的封装

    public void fenbuNoDependTable() {
        HashMap<String, Integer> hashMapCntPerRecords = new HashMap<>();
        hashMapCntPerRecords.put("44060000", 20);
        hashMapCntPerRecords.put("44010000", 13);

        ArrayList<String> fieldXOfTableBList = new ArrayList<>();
        fieldXOfTableBList.add("1064312");
        fieldXOfTableBList.add("1074312");
        fieldXOfTableBList.add("1086431");

        /*
         * 应用场景描述:
         * 1. 场景一:往表A批量插入数据,表A的字段X的值的分布要符合几何分布并且值要从另外一个表B的字段X来获取。(表B字段X的值的集合我称为数据池)
         * 2. 场景二:若要先遍历一个临时表,该临时表存了表A的Y字段的分布及其数量,比如省机构和插入数量(插入数量也满足几何分布),则在遍历该临时表时,
         *   且根据临时表的插入数量来fori循环时,也可用这个。
         *   例子:
         *   | 表A的Y字段, 插入数量|
         *   | 44060000,   20   |          =>>     fori 循环20次  =>  即该20条记录的字段X的值需满足几何分布。
         *   | 44010000,   13   |          =>>     fori 循环13次  =>  即该13条记录的字段X的值需满足几何分布
         *   (提醒:Y字段已经满足几何分布了,插入数据20、13就已经是几何分布计算出来的值)
         *
         *
         * */

        // 几何分布的p
        float p = 0.3f; // 最大数量占比(这个比例来自于字段X的各值的最大数量占总数量的比例,即'group by 字段X order by count(字段X) desc'的最大数量占总数量的比例)
        int k = 1; // 几何分布的k次数,不能和cntCurRowOfDataPool一致,因为会出现k > cntCurRowOfDataPool的情况。这时候我们需要将cntCurRowOfDataPool重置为1,重新循环
        int curRowOfDataPool = 1;// 当前数据池的第几个值。(对应表B的字段X)
        int cntCurRowOfDataPool = 1; // 数据池当前值使用了多少次。(数据池的当前值已经往表A插入了多少条数据,即使用了多少次)
        double pbtyGeometric; // 每k次的几何分布概率。(随k增大而递减)
        double pbtyActual; // 实际概率 (cntCurRowOfDataPool除以总数)
        for (Map.Entry<String, Integer> entry : hashMapCntPerRecords.entrySet()) {
            // 这里每轮都要把这三个值重置为1(如果不是在循环内,就不用重置为1)
            curRowOfDataPool = 1;
            cntCurRowOfDataPool = 1;
            k = 1;
            for (int i = 1; i <= entry.getValue(); i++) {
                System.out.println("-------进入--------");
                pbtyGeometric = Math.pow(p, k - 1) * p;
                pbtyActual = (double) cntCurRowOfDataPool / entry.getValue();

                System.out.print("pbtyActual: " + pbtyActual);
                System.out.println(";        pbtyGeometric: " + pbtyGeometric);


                if (pbtyActual > pbtyGeometric) {
                    System.out.println("超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值");
                    // 使用数据池下一个值
                    curRowOfDataPool++;
                    // 使用数据池下一个值的同时,几何分布的k也要+1,此时下一轮几何分布概率会变化,减小
                    k++;

                    // 数据池该值使用次数重置为1
                    cntCurRowOfDataPool = 1;

                    // 如果curRowOfDataPool超过数据池的值的数量,则重置为1
                    if (curRowOfDataPool > fieldXOfTableBList.size()) {
                        curRowOfDataPool = 1;
                    }
                } else {
                    // 如果没有超过几何分布的概率
                    cntCurRowOfDataPool++;

                }
                System.out.println("curRowOfDataPool: " + curRowOfDataPool);
                System.out.println("机构:" + entry.getKey() + "; 第" + i + "次; " + "virtualGiftNo为" + fieldXOfTableBList.get(curRowOfDataPool - 1));
            }
        }
    }

运行结果 

-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44010000; 第1次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.15384615384615385;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44010000; 第2次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.23076923076923078;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44010000; 第3次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.3076923076923077;        pbtyGeometric: 0.30000001192092896
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44010000; 第4次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 0.09000000715255752
curRowOfDataPool: 2
机构:44010000; 第5次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.15384615384615385;        pbtyGeometric: 0.09000000715255752
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44010000; 第6次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 0.027000003218650946
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44010000; 第7次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 0.008100001287460403
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44010000; 第8次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 0.002430000482797661
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44010000; 第9次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 7.290001738071614E-4
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44010000; 第10次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 2.187000608325077E-4
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44010000; 第11次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 6.56100208568602E-5
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44010000; 第12次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.07692307692307693;        pbtyGeometric: 1.9683007039190456E-5
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44010000; 第13次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第1次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.1;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第2次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.15;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第3次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.2;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第4次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.25;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第5次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.3;        pbtyGeometric: 0.30000001192092896
curRowOfDataPool: 1
机构:44060000; 第6次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.35;        pbtyGeometric: 0.30000001192092896
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44060000; 第7次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 0.09000000715255752
curRowOfDataPool: 2
机构:44060000; 第8次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.1;        pbtyGeometric: 0.09000000715255752
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44060000; 第9次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 0.027000003218650946
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44060000; 第10次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 0.008100001287460403
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44060000; 第11次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 0.002430000482797661
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44060000; 第12次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 7.290001738071614E-4
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44060000; 第13次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 2.187000608325077E-4
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44060000; 第14次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 6.56100208568602E-5
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44060000; 第15次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 1.9683007039190456E-5
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44060000; 第16次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 5.904902346396865E-6
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44060000; 第17次; fieldX的值为1074312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 1.7714707743109811E-6
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 3
机构:44060000; 第18次; fieldX的值为1086431
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 5.314412534108716E-7
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 1
机构:44060000; 第19次; fieldX的值为1064312
-------进入--------
pbtyActual: 0.05;        pbtyGeometric: 1.594323823585349E-7
超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值
curRowOfDataPool: 2
机构:44060000; 第20次; fieldX的值为1074312

Process finished with exit code 0

版本二:仅返回符合几何分布的数据池的第几行

    /*
     * @Title: 几何分布核心
     * @Description: 你给我传入总数和当前数量,我就能返回符合几何分布的数据池的index
     * @param p: 几何分布的成功概率
     * @param curRowOriTable: 原表的当前插入行数(次数)
     * @param cntTotal: 需要插入数据的总数
     * @param dataPoolList: 需要符合几何分布的数据池
     * @return
     */
    public static int geometricDisCore(float p, int curRowOriTable, int cntTotal, int dataPoolSize) {
        int k = 1;
        int curRowOfDataPool = 1;// 当前数据池的第几个值。
        int cntCurRowOfDataPool = 1; // 数据池当前值已经使用的次数
        double pbtyGeometric; // 第k次的几何分布概率。(随k增大而递减)
        double pbtyActual; // 实际概率 (cntCurRowOfDataPool除以总数)

        for (int i = 1; i <= curRowOriTable; i++) {
            System.out.println("---------------------进入----------------------");
            pbtyGeometric = Math.pow(p, k - 1) * p;
            pbtyActual = (double) cntCurRowOfDataPool / cntTotal;

            System.out.print("pbtyActual: " + pbtyActual);
            System.out.println(";        pbtyGeometric: " + pbtyGeometric);

            if (pbtyActual > pbtyGeometric) {
                System.out.println("超过本轮几何分布的概率, 即本次插入需要使用数据池下一个值"); // 这里其实本轮插入使用数据池当前值或下一个值都可以
                // 使用数据池下一个值
                curRowOfDataPool++;
                // 几何分布的k要自增。(但k不能和curRowOfDataPool共同使用,因为curRowOfDataPool会重置为1)
                k++;

                // 如果curRowOfDataPool超过数据池的值的数量,则重置为1
                if (curRowOfDataPool > dataPoolSize) {
                    curRowOfDataPool = 1;
                }
                // 数据池当前值已使用次数要重置为1,因为要计算数据池下一个值的次数。
                cntCurRowOfDataPool = 1;
            }
            cntCurRowOfDataPool++;
            System.out.println("curRowOfDataPool: " + curRowOfDataPool);

        }
        return curRowOfDataPool;
    }
}

    public void exec() {
        int index;
        ArrayList<Object> indexList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            index = geometricDisCore(0.3f, i, 10, 3);
            indexList.add(index);
        }
        System.out.println(indexList);
    }

/* 输出:[1, 1, 1, 2, 3, 1, 2, 3, 1, 2] */

版本二的oracle函数版本

create FUNCTION geometricDisForIndex(p in float, curRowOriTable in int, cntTotal in int, dataPoolSize in int)
  RETURN int
AS
  k int := 1; -- 几何分布的k
  curRowOfDataPool int := 1; -- 当前数据池的第几个值。
  cntCurRowOfDataPool int := 1; --
  pbtyGeometric float;
  pbtyActual float;

BEGIN
    for i in 1.. curRowOriTable loop
        pbtyGeometric := power(p, k-1) * p;
        pbtyActual := cntCurRowOfDataPool / cntTotal;
        --DBMS_OUTPUT.PUT_LINE('实际概率'|| TRUNC(pbtyActual,3)||';  几何分布概率:'||TRUNC(pbtyGeometric,3));
        IF pbtyActual > pbtyGeometric THEN
            --DBMS_OUTPUT.PUT_LINE('超过本轮几何分布概率,此时使用数据池下一个值');
            -- 使用数据池下一个值
            curRowOfDataPool := curRowOfDataPool + 1;
            -- 几何分布的k要自增。(但k不能和curRowOfDataPool共同使用,因为curRowOfDataPool会重置为1)
            k := k + 1;

            -- 如果curRowOfDataPool超过数据池的值的数量,则重置为1
            IF curRowOfDataPool > dataPoolSize THEN
                curRowOfDataPool := 1;
            end if;

            -- 数据池当前值已使用次数要重置为1,因为要计算数据池下一个值的次数。
            cntCurRowOfDataPool := 1;
        end if;
        cntCurRowOfDataPool := cntCurRowOfDataPool + 1;
        --DBMS_OUTPUT.PUT_LINE('curRowOfDataPool: '||curRowOfDataPool);
    end loop;
    return curRowOfDataPool;
END geometricDisForIndex;
/

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值