main.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package main
  2. import (
  3. "TsDB2/DB"
  4. "fmt"
  5. "os"
  6. "time"
  7. )
  8. // ========== 数据模型 ==========
  9. type Employee struct {
  10. DB.BaseModel
  11. Name string `vrtx:"maxlen:32"`
  12. Age int64 `vrtx:"index:idx_age"`
  13. Score int64
  14. Dept string `vrtx:"maxlen:16,index:idx_dept"`
  15. }
  16. type Order struct {
  17. DB.BaseModel
  18. EmployeeID int64
  19. Amount int64
  20. Status int64 `vrtx:"index:idx_status"`
  21. }
  22. const dbPath = "fulltest.db"
  23. const N = 100_000
  24. func main() {
  25. os.Remove(dbPath)
  26. passed := 0
  27. failed := 0
  28. check := func(name string, ok bool, detail string) {
  29. if ok {
  30. passed++
  31. fmt.Printf(" ✅ %s\n", name)
  32. } else {
  33. failed++
  34. fmt.Printf(" ❌ %s — %s\n", name, detail)
  35. }
  36. }
  37. // =============================================
  38. fmt.Println("========== 1. 打开数据库 + 建表 ==========")
  39. // =============================================
  40. db, err := DB.Open(dbPath)
  41. if err != nil {
  42. panic(err)
  43. }
  44. // 禁用自动提交, 手动控制 Commit 时机 (百万行插入时避免中间 Commit)
  45. db.SetAutoCommitDelay(0)
  46. empTbl, err := DB.UseTable[Employee](db, "employee")
  47. if err != nil {
  48. panic(err)
  49. }
  50. // 二级索引已通过 vrtx 标签自动创建: idx_age, idx_dept
  51. orderTbl, err := DB.UseTable[Order](db, "order")
  52. if err != nil {
  53. panic(err)
  54. }
  55. // 二级索引已通过 vrtx 标签自动创建: idx_status
  56. fmt.Println(" 表 employee: ID + Name(32byte) + Age(8byte) + Score(8byte) + Dept(16byte)")
  57. fmt.Println(" 索引: pk_employee, idx_age, idx_dept")
  58. fmt.Println(" 表 order: ID + EmployeeID(8byte) + Amount(8byte) + Status(8byte)")
  59. fmt.Println(" 索引: pk_order, idx_status")
  60. // =============================================
  61. fmt.Println("\n========== 2. 批量插入 100万行 ==========")
  62. // =============================================
  63. depts := []string{"Eng", "Sales", "HR", "Fin", "Ops"}
  64. t0 := time.Now()
  65. for i := 1; i <= N; i++ {
  66. err := empTbl.Insert(&Employee{
  67. Name: fmt.Sprintf("Emp%07d", i),
  68. Age: int64(20 + (i % 50)),
  69. Score: int64(i % 1000),
  70. Dept: depts[i%5],
  71. })
  72. if err != nil {
  73. panic(fmt.Sprintf("insert row %d: %v", i, err))
  74. }
  75. if i%20000 == 0 {
  76. fmt.Printf(" 已插入 %d 行 (%.1fs)\n", i, time.Since(t0).Seconds())
  77. }
  78. }
  79. // 手动 Commit 所有数据
  80. fmt.Println(" 插入完成, 开始 Commit...")
  81. t1 := time.Now()
  82. if err := db.Commit(); err != nil {
  83. panic(err)
  84. }
  85. insertTime := time.Since(t0)
  86. fmt.Printf(" ✅ 插入 %d 行 + Commit 完成, 耗时 %.1fs (Commit %.1fs)\n", N, insertTime.Seconds(), time.Since(t1).Seconds())
  87. // =============================================
  88. fmt.Println("\n========== 3. 主键查询 ==========")
  89. // =============================================
  90. // 精确查找
  91. row, err := empTbl.Find(1)
  92. check("PK 精确查找 id=1", err == nil && row.Name == "Emp0000001",
  93. fmt.Sprintf("err=%v name=%s", err, row.Name))
  94. row, err = empTbl.Find(uint64(N / 2))
  95. rn := ""
  96. if row != nil {
  97. rn = row.Name
  98. }
  99. check(fmt.Sprintf("PK 精确查找 id=%d", N/2), err == nil && row != nil && row.Name == fmt.Sprintf("Emp%07d", N/2),
  100. fmt.Sprintf("err=%v name=%s", err, rn))
  101. row, err = empTbl.Find(uint64(N))
  102. rn = ""
  103. if row != nil {
  104. rn = row.Name
  105. }
  106. check(fmt.Sprintf("PK 精确查找 id=%d", N), err == nil && row != nil && row.Name == fmt.Sprintf("Emp%07d", N),
  107. fmt.Sprintf("err=%v name=%s", err, rn))
  108. // =============================================
  109. fmt.Println("\n========== 4. 条件查询 ==========")
  110. // =============================================
  111. // WHERE age = 25
  112. t2 := time.Now()
  113. rows, err := empTbl.Where("Age", "=", int64(25)).Find()
  114. check("WHERE Age=25", err == nil && len(rows) > 0,
  115. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  116. fmt.Printf(" 返回 %d 行, 耗时 %.3fs\n", len(rows), time.Since(t2).Seconds())
  117. // WHERE age > 60
  118. t2 = time.Now()
  119. rows, err = empTbl.Where("Age", ">", int64(60)).Find()
  120. check("WHERE Age>60", err == nil && len(rows) > 0,
  121. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  122. fmt.Printf(" 返回 %d 行, 耗时 %.3fs\n", len(rows), time.Since(t2).Seconds())
  123. // WHERE age >= 20 AND age <= 25
  124. t2 = time.Now()
  125. rows, err = empTbl.Where("Age", ">=", int64(20)).Where("Age", "<=", int64(25)).Find()
  126. check("WHERE Age>=20 AND Age<=25", err == nil && len(rows) > 0,
  127. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  128. fmt.Printf(" 返回 %d 行, 耗时 %.3fs\n", len(rows), time.Since(t2).Seconds())
  129. // WHERE score = 999
  130. t2 = time.Now()
  131. rows, err = empTbl.Where("Score", "=", int64(999)).Find()
  132. check("WHERE Score=999 (全表扫描)", err == nil && len(rows) > 0,
  133. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  134. fmt.Printf(" 返回 %d 行, 耗时 %.3fs\n", len(rows), time.Since(t2).Seconds())
  135. // =============================================
  136. fmt.Println("\n========== 5. 排序 + 分页 ==========")
  137. // =============================================
  138. // ORDER BY Age ASC LIMIT 10
  139. t2 = time.Now()
  140. rows, err = empTbl.OrderBy("Age").Limit(10).Find()
  141. check("ORDER BY Age ASC LIMIT 10", err == nil && len(rows) == 10,
  142. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  143. if len(rows) >= 2 {
  144. check(" 排序正确 (前2行 Age 递增)", rows[0].Age <= rows[1].Age,
  145. fmt.Sprintf("age[0]=%d age[1]=%d", rows[0].Age, rows[1].Age))
  146. }
  147. fmt.Printf(" 耗时 %.3fs\n", time.Since(t2).Seconds())
  148. // ORDER BY Age DESC LIMIT 5
  149. rows, err = empTbl.OrderBy("Age", true).Limit(5).Find()
  150. check("ORDER BY Age DESC LIMIT 5", err == nil && len(rows) == 5,
  151. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  152. if len(rows) >= 2 {
  153. check(" 排序正确 (前2行 Age 递减)", rows[0].Age >= rows[1].Age,
  154. fmt.Sprintf("age[0]=%d age[1]=%d", rows[0].Age, rows[1].Age))
  155. }
  156. // OFFSET + LIMIT
  157. rows, err = empTbl.OrderBy("Age").Offset(100).Limit(5).Find()
  158. check("ORDER BY Age OFFSET 100 LIMIT 5", err == nil && len(rows) == 5,
  159. fmt.Sprintf("err=%v count=%d", err, len(rows)))
  160. // =============================================
  161. fmt.Println("\n========== 6. 聚合查询 ==========")
  162. // =============================================
  163. t2 = time.Now()
  164. cnt, err := empTbl.Count()
  165. check("COUNT(*)", err == nil && cnt == int64(N),
  166. fmt.Sprintf("err=%v count=%d", err, cnt))
  167. fmt.Printf(" COUNT=%d, 耗时 %.3fs\n", cnt, time.Since(t2).Seconds())
  168. // =============================================
  169. fmt.Println("\n========== 7. 第二张表: 插入 + 关联查询 ==========")
  170. // =============================================
  171. orderN := 10_000
  172. t2 = time.Now()
  173. for i := 1; i <= orderN; i++ {
  174. err := orderTbl.Insert(&Order{
  175. EmployeeID: int64(1 + (i % N)),
  176. Amount: int64(100 + (i % 500)),
  177. Status: int64(i % 4), // 0=pending 1=done 2=cancel 3=refund
  178. })
  179. if err != nil {
  180. panic(err)
  181. }
  182. if i%5000 == 0 {
  183. fmt.Printf(" 已插入 %d 行 (%.1fs)\n", i, time.Since(t2).Seconds())
  184. }
  185. }
  186. db.Commit()
  187. fmt.Printf(" ✅ 插入 %d 行 Order + Commit, 耗时 %.1fs\n", orderN, time.Since(t2).Seconds())
  188. // 查 order 的 status
  189. rows2, _ := orderTbl.Where("Status", "=", int64(0)).Find()
  190. fmt.Printf(" Order WHERE Status=0: %d 行\n", len(rows2))
  191. check("Order WHERE Status=0", len(rows2) > 0, "should have results")
  192. // =============================================
  193. fmt.Println("\n========== 8. 更新操作 ==========")
  194. // =============================================
  195. // 更新 id=1 的 employee
  196. t2 = time.Now()
  197. err = empTbl.Update(&Employee{
  198. BaseModel: DB.BaseModel{ID: 1},
  199. Name: "Updated_Emp0000001",
  200. Age: 99,
  201. Score: 0,
  202. Dept: "VIP",
  203. })
  204. check("UPDATE id=1", err == nil, fmt.Sprintf("err=%v", err))
  205. db.Commit()
  206. // 验证更新
  207. row, err = empTbl.Find(1)
  208. check("UPDATE 后验证", err == nil && row.Name == "Updated_Emp0000001" && row.Age == 99,
  209. fmt.Sprintf("err=%v name=%s age=%d", err, row.Name, row.Age))
  210. fmt.Printf(" 更新+Commit 耗时 %.3fs\n", time.Since(t2).Seconds())
  211. // =============================================
  212. fmt.Println("\n========== 9. 删除操作 ==========")
  213. // =============================================
  214. // 删除 id=2
  215. t2 = time.Now()
  216. err = empTbl.Delete(2)
  217. check("DELETE id=2", err == nil, fmt.Sprintf("err=%v", err))
  218. db.Commit()
  219. // 验证删除
  220. _, err = empTbl.Find(2)
  221. check("DELETE 后验证 (应找不到)", err != nil, "should not find id=2")
  222. // 删除 id=3~12 (10行)
  223. for i := 3; i <= 12; i++ {
  224. empTbl.Delete(uint64(i))
  225. }
  226. db.Commit()
  227. cnt, _ = empTbl.Count()
  228. check("DELETE 11行后 COUNT", cnt == int64(N-11),
  229. fmt.Sprintf("expected %d, got %d", N-11, cnt))
  230. fmt.Printf(" 删除+Commit 耗时 %.3fs\n", time.Since(t2).Seconds())
  231. // =============================================
  232. fmt.Println("\n========== 10. 关闭 + 重开验证持久化 ==========")
  233. // =============================================
  234. db.Close()
  235. db2, err := DB.Open(dbPath)
  236. if err != nil {
  237. panic(err)
  238. }
  239. db2.SetAutoCommitDelay(0) // 手动模式
  240. empTbl2, _ := DB.UseTable[Employee](db2, "employee")
  241. orderTbl2, _ := DB.UseTable[Order](db2, "order")
  242. cnt, _ = empTbl2.Count()
  243. check("重开后 employee COUNT", cnt == int64(N-11),
  244. fmt.Sprintf("expected %d, got %d", N-11, cnt))
  245. cnt2, _ := orderTbl2.Count()
  246. check("重开后 order COUNT", cnt2 == int64(orderN),
  247. fmt.Sprintf("expected %d, got %d", orderN, cnt2))
  248. // 验证更新持久化
  249. row, _ = empTbl2.Find(1)
  250. check("重开后 UPDATE 持久化", row.Name == "Updated_Emp0000001" && row.Age == 99,
  251. fmt.Sprintf("name=%s age=%d", row.Name, row.Age))
  252. // 验证删除持久化
  253. _, err = empTbl2.Find(2)
  254. check("重开后 DELETE 持久化", err != nil, "id=2 should be deleted")
  255. // =============================================
  256. fmt.Println("\n========== 11. 防抖自动提交测试 ==========")
  257. // =============================================
  258. db2.SetAutoCommitDelay(500 * time.Millisecond)
  259. // 插入几行, 等自动提交
  260. for i := N + 1; i <= N+100; i++ {
  261. empTbl2.Insert(&Employee{
  262. Name: fmt.Sprintf("Auto%04d", i-N), Age: 30, Score: 50, Dept: "Auto",
  263. })
  264. }
  265. fmt.Println(" 插入 100 行, 等待防抖自动提交 (500ms)...")
  266. time.Sleep(1 * time.Second)
  267. // 关闭再重开验证
  268. db2.Close()
  269. db3, _ := DB.Open(dbPath)
  270. empTbl3, _ := DB.UseTable[Employee](db3, "employee")
  271. cnt, _ = empTbl3.Count()
  272. expected := int64(N - 11 + 100)
  273. check("防抖自动提交后重开 COUNT", cnt == expected,
  274. fmt.Sprintf("expected %d, got %d", expected, cnt))
  275. db3.Close()
  276. // =============================================
  277. fmt.Println("\n========== 12. 删除表 + 空闲页回收 ==========")
  278. // =============================================
  279. db4, _ := DB.Open(dbPath)
  280. db4.SetAutoCommitDelay(0)
  281. // 记录删除前的空闲页数
  282. beforeFree := db4.CoreDB().DebugFreePageCount()
  283. fmt.Printf(" 删除表前 FreePageCount=%d\n", beforeFree)
  284. // 删除 order 表
  285. err = db4.DropTable("order")
  286. check("DropTable order", err == nil, fmt.Sprintf("err=%v", err))
  287. db4.Commit()
  288. afterFree := db4.CoreDB().DebugFreePageCount()
  289. fmt.Printf(" 删除表后 FreePageCount=%d (回收 %d 页)\n", afterFree, afterFree-beforeFree)
  290. check("删除表后空闲页增加", afterFree > beforeFree,
  291. fmt.Sprintf("before=%d after=%d", beforeFree, afterFree))
  292. // 验证 order 表已不存在
  293. _, ok := db4.CoreDB().FindTable("order")
  294. check("order 表已不存在", !ok, "order table should not exist")
  295. // employee 表仍正常
  296. empTbl4, _ := DB.UseTable[Employee](db4, "employee")
  297. cnt, _ = empTbl4.Count()
  298. check("employee 表不受影响", cnt == expected,
  299. fmt.Sprintf("expected %d, got %d", expected, cnt))
  300. db4.Close()
  301. // =============================================
  302. fmt.Printf("\n============================================\n")
  303. fmt.Printf("测试结果: %d 通过, %d 失败\n", passed, failed)
  304. if failed == 0 {
  305. fmt.Println("🎉 全部通过!")
  306. } else {
  307. fmt.Printf("⚠️ 有 %d 项失败\n", failed)
  308. }
  309. }