"""伝票明細を何行まで積むと、引き当てと月の集計がどれだけ遅くなるかを測る(SQLite、標準ライブラリだけ)。
架空の明細(得意先300社・商品2,000点・乱数の種 20261016)を N 行入れ、
(1) 得意先×商品の明細を1件引く、(2) 得意先1社の1か月分の明細を合計する、を各200回測り、中央値を出す。
実行: python db_rows_limit.py   (結果は標準出力。環境は実行時に表示)"""
import os, platform, random, sqlite3, statistics, sys, tempfile, time

random.seed(20261016)
CUST, ITEMS = 300, 2000

def run(n):
    path = os.path.join(tempfile.mkdtemp(), "t.db")
    con = sqlite3.connect(path)
    con.execute("create table line(id integer primary key, cust int, item int, ym int, qty int, price int)")
    t0 = time.perf_counter()
    rows = ((i, random.randrange(CUST), random.randrange(ITEMS), 202000 + random.randrange(1, 61), random.randrange(1, 50), random.randrange(100, 20000)) for i in range(n))
    con.executemany("insert into line values(?,?,?,?,?,?)", rows)
    con.commit()
    ins = time.perf_counter() - t0
    con.execute("create index ix_cust_ym on line(cust, ym)")
    con.execute("create index ix_cust_item on line(cust, item)")
    con.commit()
    def med(sql, gen):
        ts = []
        for _ in range(200):
            a = gen(); t = time.perf_counter(); con.execute(sql, a).fetchall(); ts.append((time.perf_counter() - t) * 1000)
        return statistics.median(ts)
    q1 = med("select price from line where cust=? and item=? order by id desc limit 1", lambda: (random.randrange(CUST), random.randrange(ITEMS)))
    q2 = med("select sum(qty*price) from line where cust=? and ym=?", lambda: (random.randrange(CUST), 202000 + random.randrange(1, 61)))
    size = os.path.getsize(path) / 1e6
    con.close()
    return ins, q1, q2, size

if __name__ == "__main__":
    print(f"Python {platform.python_version()}, SQLite {sqlite3.sqlite_version}, {platform.platform()}, CPU {platform.processor()}")
    print("行数, 入れる秒, 単価1件の引き当て(ms), 得意先1社の1か月合計(ms), ファイル(MB)")
    for n in (600_000, 2_400_000, 6_000_000):
        ins, q1, q2, size = run(n)
        print(f"{n:,}, {ins:.1f}, {q1:.3f}, {q2:.3f}, {size:.0f}")
