diff --git a/examples/bench_heavy.prg b/examples/bench_heavy.prg new file mode 100644 index 0000000..70aeb69 --- /dev/null +++ b/examples/bench_heavy.prg @@ -0,0 +1,174 @@ +// Heavy RDD benchmark — 50K records, multiple indexes, mixed operations + + +PROCEDURE Main() + LOCAL i, j, nH, nStart, nEnd, nCount, nSum + LOCAL aStruct, aCities, nIdx + + ErrorBlock({|e| Break(e)}) + aCities := {"Seoul","Tokyo","Beijing","London","NYC","Paris","Berlin","Rome","Madrid","Oslo"} + + aStruct := { ; + {"ID","N",8,0}, {"NAME","C",30,0}, {"CITY","C",15,0}, ; + {"SALARY","N",12,2}, {"ACTIVE","L",1,0}, {"CODE","C",10,0} ; + } + + BEGIN SEQUENCE + + // ======== APPEND 50K ======== + nStart := Seconds() + dbCreate("heavy_test", aStruct) + USE "heavy_test" NEW + FOR i := 1 TO 50000 + APPEND BLANK + REPLACE ID WITH i + REPLACE NAME WITH PadR("Name_" + PadL(LTrim(Str(i)), 5, "0"), 30) + nIdx := ((i-1) % 10) + 1 + REPLACE CITY WITH PadR(aCities[nIdx], 15) + REPLACE SALARY WITH 20000 + i * 1.50 + REPLACE ACTIVE WITH (i % 3 != 0) + REPLACE CODE WITH PadR(LTrim(Str(Int(((i-1)/500))+1)), 10) + NEXT + nEnd := Seconds() + R("H1_APPEND_50K", FmtMs(nEnd - nStart) + " rc=" + LTrim(Str(RecCount()))) + + // ======== INDEX 50K ======== + nStart := Seconds() + INDEX ON FIELD->NAME TO heavy_name + nEnd := Seconds() + R("H2_INDEX_50K", FmtMs(nEnd - nStart)) + CLOSE ALL + + // ======== SEEK 50K sequential ======== + USE "heavy_test" NEW + SET INDEX TO heavy_name + nStart := Seconds() + nCount := 0 + FOR i := 1 TO 50000 + SEEK PadR("Name_" + PadL(LTrim(Str(i)), 5, "0"), 30) + IF Found() + nCount++ + ENDIF + NEXT + nEnd := Seconds() + R("H3_SEEK_50K", FmtMs(nEnd - nStart) + " f=" + LTrim(Str(nCount))) + + // ======== SEEK 50K random ======== + nStart := Seconds() + nCount := 0 + FOR i := 1 TO 50000 + j := ((i * 7919) % 50000) + 1 + SEEK PadR("Name_" + PadL(LTrim(Str(j)), 5, "0"), 30) + IF Found() + nCount++ + ENDIF + NEXT + nEnd := Seconds() + R("H4_SEEK_RND", FmtMs(nEnd - nStart) + " f=" + LTrim(Str(nCount))) + CLOSE ALL + + // ======== FULL SCAN 50K ======== + USE "heavy_test" NEW + SET INDEX TO heavy_name + nStart := Seconds() + GO TOP + nCount := 0 + DO WHILE !EOF() + nCount++ + SKIP + ENDDO + nEnd := Seconds() + R("H5_SCAN_50K", FmtMs(nEnd - nStart) + " c=" + LTrim(Str(nCount))) + CLOSE ALL + + // ======== CITY INDEX 50K ======== + USE "heavy_test" NEW + nStart := Seconds() + INDEX ON FIELD->CITY TO heavy_city + nEnd := Seconds() + R("H6_IDX_CITY", FmtMs(nEnd - nStart)) + + // ======== DUP KEY SEEK+SCAN ======== + nStart := Seconds() + nCount := 0 + FOR i := 1 TO 10 + SEEK PadR(aCities[i], 15) + DO WHILE !EOF() .AND. RTrim(FieldGet(3)) == aCities[i] + nCount++ + SKIP + ENDDO + NEXT + nEnd := Seconds() + R("H7_DUPKEY_50K", FmtMs(nEnd - nStart) + " c=" + LTrim(Str(nCount))) + CLOSE ALL + + // ======== DELETE 10K + SET DELETED SCAN ======== + USE "heavy_test" NEW + SET INDEX TO heavy_name + SET ORDER TO 0 + FOR i := 1 TO 50000 + GO i + IF i % 5 == 0 + DELETE + ENDIF + NEXT + + SET ORDER TO 1 + SET DELETED ON + nStart := Seconds() + GO TOP + nCount := 0 + DO WHILE !EOF() + nCount++ + SKIP + ENDDO + nEnd := Seconds() + R("H8_DELSCAN_50K", FmtMs(nEnd - nStart) + " c=" + LTrim(Str(nCount))) + + SET DELETED OFF + SET ORDER TO 0 + FOR i := 1 TO 50000 + GO i + IF Deleted() + RECALL + ENDIF + NEXT + CLOSE ALL + + // ======== COMPOUND INDEX ======== + USE "heavy_test" NEW + nStart := Seconds() + INDEX ON FIELD->CITY + FIELD->NAME TO heavy_comp + nEnd := Seconds() + R("H9_IDX_COMP", FmtMs(nEnd - nStart)) + + SEEK PadR("Seoul", 15) + PadR("Name_00001", 30) + R("H10_COMP_SEEK", IIF(Found(),".T.",".F.") + " " + LTrim(Str(RecNo()))) + CLOSE ALL + + // ======== PACK 50K (10K deleted) ======== + USE "heavy_test" NEW + FOR i := 1 TO 50000 + GO i + IF i % 5 == 0 + DELETE + ENDIF + NEXT + nStart := Seconds() + PACK + nEnd := Seconds() + R("H11_PACK_50K", FmtMs(nEnd - nStart) + " rc=" + LTrim(Str(RecCount()))) + CLOSE ALL + + RECOVER + ? "ERROR" + END SEQUENCE + +RETURN + +FUNCTION FmtMs(nSec) +RETURN LTrim(Str(Int(nSec * 1000))) + "ms" + +PROCEDURE R(cKey, cVal) + ? cKey + "=" + cVal +RETURN