// 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