query.go 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. package core
  2. import (
  3. "TsDB2/DB/core/index"
  4. "TsDB2/DB/core/page"
  5. "TsDB2/DB/core/types"
  6. "bytes"
  7. "encoding/binary"
  8. "fmt"
  9. "math/big"
  10. "sort"
  11. )
  12. // Query 查询操作对象
  13. type Query struct {
  14. table *Table
  15. selectCols []string // SELECT 字段列表
  16. whereCond Condition // WHERE 条件
  17. orderBys []SortField // ORDER BY
  18. limit int // LIMIT
  19. offset int // OFFSET
  20. groupBys []string // GROUP BY
  21. havingCond Condition // HAVING
  22. }
  23. type SortField struct {
  24. Field string
  25. Descending bool
  26. }
  27. // scanPlan 索引扫描计划
  28. type scanPlan struct {
  29. meta *IndexMeta
  30. handler index.IndexHandler
  31. startKey []byte
  32. endKey []byte
  33. startInclusive bool
  34. endInclusive bool
  35. rowStore bool // 该索引是否承载行数据 (主键/时序=true)
  36. remainingCond Condition // 需要行级过滤的剩余条件
  37. }
  38. // Query 返回查询操作对象
  39. func (table *Table) Query() *Query {
  40. return &Query{table: table}
  41. }
  42. func (q *Query) Select(cols ...string) *Query { q.selectCols = cols; return q }
  43. func (q *Query) Where(cond Condition) *Query { q.whereCond = cond; return q }
  44. func (q *Query) Limit(n int) *Query { q.limit = n; return q }
  45. func (q *Query) Offset(n int) *Query { q.offset = n; return q }
  46. func (q *Query) GroupBy(cols ...string) *Query { q.groupBys = cols; return q }
  47. func (q *Query) Having(cond Condition) *Query { q.havingCond = cond; return q }
  48. func (q *Query) OrderBy(field string, descending ...bool) *Query {
  49. desc := false
  50. if len(descending) > 0 {
  51. desc = descending[0]
  52. }
  53. q.orderBys = append(q.orderBys, SortField{Field: field, Descending: desc})
  54. return q
  55. }
  56. // ======================== 索引键编码 ========================
  57. // encodeIndexKey 将条件值编码为索引键字节。
  58. //
  59. // 编码与行内存储【同源】(都走 types.EncodeValue): 索引的 B+ 树直接按字节序比较键,
  60. // 因此"索引键字节 == 行内字节"是范围扫描正确的前提。这里不再按类型手写分支 ——
  61. // 以前每加一个类型都要在这里补一份, 漏补的后果是索引选出来的行与过滤结果不一致。
  62. //
  63. // param 是列级类型参数: decimal 是小数位数, 字符串家族是行内宽度码。少了它就没法把
  64. // 条件值编成与行内完全一致的字节 —— decimal 会因 scale 不同而长度/系数不一致,
  65. // 字符串则会按错误的宽度截断或越界, 两种都让"索引选出 5 行、过滤后剩 0 行"。
  66. //
  67. // 键长必须等于 FieldSize(ft, param): B+ 树按【定长拼键】比较, 键长与行内宽度不一致
  68. // 就等于拿两种编码去比大小。
  69. func encodeIndexKey(value interface{}, ft types.FieldType, param byte) []byte {
  70. if types.IsDynamic(ft) {
  71. // 动态列不能作为索引分量 (CreateIndex 已拒绝), 这里仅作兜底
  72. if b, ok := value.([]byte); ok {
  73. return b
  74. }
  75. return nil
  76. }
  77. size := types.FieldSize(ft, param)
  78. if size == 0 {
  79. // 未注册类型 / 非法列参数: 交给下面 EncodeValue 报出具体原因 (buf 长度为 0)
  80. panic(fmt.Errorf("%w: 类型 %s 的宽度不可计算 (列级参数 %d)",
  81. types.ErrValueType, types.TypeNameOf(ft), param))
  82. }
  83. buf := make([]byte, size)
  84. if err := types.EncodeValue(ft, param, value, buf); err != nil {
  85. // 沿用既有约定: panic 由 encodeIndexKeySafe* 转成 error。
  86. panic(err)
  87. }
  88. return buf
  89. }
  90. // encodeIndexKeySafe 在 encodeIndexKey 外面包一层 panic 恢复。
  91. // 值类型与列不符时 encodeIndexKey 会 panic, 而公开 API 传进来的值不可信,
  92. // 必须转成 error, 不能把用户输入直接变成崩溃。
  93. func encodeIndexKeySafe(value interface{}, ft types.FieldType) (enc []byte, err error) {
  94. return encodeIndexKeySafeWithParam(value, ft, 0)
  95. }
  96. // encodeIndexKeySafeWithParam 同 encodeIndexKeySafe, 但带上列级类型参数。
  97. // 查询侧拿得到字段元信息时必须走这个版本 (decimal 需要 param 才能编出正确的字节)。
  98. func encodeIndexKeySafeWithParam(value interface{}, ft types.FieldType, param byte) (enc []byte, err error) {
  99. defer func() {
  100. if r := recover(); r != nil {
  101. enc, err = nil, fmt.Errorf("值 %v 与存储类型 %s 不匹配: %v", value, types.TypeNameOf(ft), r)
  102. }
  103. }()
  104. return encodeIndexKey(value, ft, param), nil
  105. }
  106. // ======================== 索引匹配 ========================
  107. // fieldNameFromMeta 获取索引第一个字段的名称
  108. func (q *Query) fieldNameFromMeta(meta *IndexMeta) string {
  109. fieldIdx := int(meta.FieldIDs[0])
  110. if fieldIdx < len(q.table.Field) {
  111. return string(q.table.Field[fieldIdx].FieldName)
  112. }
  113. return ""
  114. }
  115. // ======================== 复合索引键规划 ========================
  116. //
  117. // 索引键 = 各分量字段定长拼接 (编码与 extractIndexKey 完全一致), 因此:
  118. // - 已知前 k 个分量等值 → 键上一段连续区间;
  119. // - 第 k+1 个分量上的范围条件 → 再收窄这段区间;
  120. // - 更靠后的分量索引帮不上忙, 原样留作行级后置过滤。
  121. // 下面的代码把 WHERE 按这个模型折叠成 (startKey, endKey, 残余条件)。
  122. //
  123. // 单列索引是 n == 1 的特例, 行为与旧实现一致。
  124. // indexKeyLayout 索引键各分量的偏移与长度 (定长拼接)
  125. type indexKeyLayout struct {
  126. offsets []int
  127. sizes []int
  128. total int
  129. }
  130. // cmpKind 叶子条件能为键分量提供的边界方向
  131. type cmpKind int
  132. const (
  133. cmpEq cmpKind = iota
  134. cmpGe
  135. cmpGt
  136. cmpLe
  137. cmpLt
  138. )
  139. // keyConstraint 某个键分量上的合并边界 (多个 AND 子条件取交集)
  140. type keyConstraint struct {
  141. lo, hi []byte // 编码后的分量值; nil 表示该侧无约束
  142. loInc, hiInc bool
  143. count int // 落在该分量上的条件个数, 0 = 无约束
  144. }
  145. // add 把一个边界并入本分量; 返回 false 表示条件自相矛盾。
  146. func (kc *keyConstraint) add(kind cmpKind, enc []byte) bool {
  147. switch kind {
  148. case cmpEq:
  149. if !kc.addLower(enc, true) || !kc.addUpper(enc, true) {
  150. return false
  151. }
  152. case cmpGe:
  153. if !kc.addLower(enc, true) {
  154. return false
  155. }
  156. case cmpGt:
  157. if !kc.addLower(enc, false) {
  158. return false
  159. }
  160. case cmpLe:
  161. if !kc.addUpper(enc, true) {
  162. return false
  163. }
  164. case cmpLt:
  165. if !kc.addUpper(enc, false) {
  166. return false
  167. }
  168. }
  169. kc.count++
  170. return true
  171. }
  172. func (kc *keyConstraint) addLower(enc []byte, inclusive bool) bool {
  173. if kc.lo == nil {
  174. kc.lo, kc.loInc = enc, inclusive
  175. return true
  176. }
  177. switch c := bytes.Compare(enc, kc.lo); {
  178. case c > 0: // 取更高的下界
  179. kc.lo, kc.loInc = enc, inclusive
  180. case c == 0: // 同值: 两端都闭才算"含"
  181. kc.loInc = kc.loInc && inclusive
  182. }
  183. return kc.notContradictory()
  184. }
  185. func (kc *keyConstraint) addUpper(enc []byte, inclusive bool) bool {
  186. if kc.hi == nil {
  187. kc.hi, kc.hiInc = enc, inclusive
  188. return true
  189. }
  190. switch c := bytes.Compare(enc, kc.hi); {
  191. case c < 0: // 取更低的上界
  192. kc.hi, kc.hiInc = enc, inclusive
  193. case c == 0:
  194. kc.hiInc = kc.hiInc && inclusive
  195. }
  196. return kc.notContradictory()
  197. }
  198. // notContradictory 判断 [lo, hi] 是否还可能有值。
  199. //
  200. // 注意: 这里按编码字节比较, 而定长整数用的是补码 —— 负数的字节序与数值序相反。
  201. // 所以它只在"字节序下已确定矛盾"时才返回 false, 此时真值也必然为空, 反向不成立。
  202. // 调用方因此只把它当作"放弃使用索引"的依据, 绝不据此断言区间非空。
  203. func (kc *keyConstraint) notContradictory() bool {
  204. if kc.lo == nil || kc.hi == nil {
  205. return true
  206. }
  207. switch c := bytes.Compare(kc.lo, kc.hi); {
  208. case c > 0:
  209. return false
  210. case c == 0:
  211. return kc.loInc && kc.hiInc
  212. }
  213. return true
  214. }
  215. // isEquality 该分量已被钉死为单值 (lo == hi 且两端都闭)
  216. func (kc *keyConstraint) isEquality() bool {
  217. return kc.count > 0 && kc.lo != nil && kc.hi != nil &&
  218. kc.loInc && kc.hiInc && bytes.Equal(kc.lo, kc.hi)
  219. }
  220. // buildKeyLayout 依据索引元信息与表字段类型算出键布局。
  221. // 返回 false 表示该索引当前不可用于查询:
  222. // - 分量列不存在或已被 Drop (新行提不出该分量, 索引里根本没有这批键);
  223. // - 分量是动态列 (行内只存 6B 堆引用, 值 != 引用, 无法按键定位)。
  224. func (q *Query) buildKeyLayout(meta *IndexMeta) (*indexKeyLayout, bool) {
  225. n := int(meta.FieldCnt)
  226. if n <= 0 || n > len(meta.FieldIDs) || n > len(q.table.Field) {
  227. return nil, false
  228. }
  229. lay := &indexKeyLayout{offsets: make([]int, n), sizes: make([]int, n)}
  230. off := 0
  231. for k := 0; k < n; k++ {
  232. fi := int(meta.FieldIDs[k])
  233. if fi >= len(q.table.Field) {
  234. return nil, false
  235. }
  236. if q.table.Field[fi].IsDropped() {
  237. return nil, false
  238. }
  239. ft := q.table.Field[fi].FieldType
  240. if types.IsDynamic(ft) {
  241. return nil, false
  242. }
  243. // 键分量宽度必须与行内宽度同源 (含字符串列的宽度码), 否则索引键的偏移切不出该列
  244. size := int(q.table.Field[fi].Width())
  245. if size <= 0 {
  246. return nil, false
  247. }
  248. lay.offsets[k] = off
  249. lay.sizes[k] = size
  250. off += size
  251. }
  252. lay.total = off
  253. return lay, true
  254. }
  255. // locateComponent 返回字段 master 下标在索引键中的分量位置; -1 表示不属于该索引
  256. func (q *Query) locateComponent(fieldName string, meta *IndexMeta) int {
  257. fi := q.table.findFieldIndex(fieldName)
  258. if fi < 0 {
  259. return -1
  260. }
  261. n := int(meta.FieldCnt)
  262. if n > len(meta.FieldIDs) {
  263. n = len(meta.FieldIDs)
  264. }
  265. for k := 0; k < n; k++ {
  266. if int(meta.FieldIDs[k]) == fi {
  267. return k
  268. }
  269. }
  270. return -1
  271. }
  272. // classifyLeaf 判断一个叶子条件能否成为某个键分量的边界。
  273. // comp < 0 表示与该索引无关 (字段不在索引里, 或该条件类型给不出可比边界)。
  274. func (q *Query) classifyLeaf(c Condition, meta *IndexMeta) (comp int, value interface{}, kind cmpKind) {
  275. switch t := c.(type) {
  276. case EqCondition:
  277. return q.locateComponent(t.Field, meta), t.Value, cmpEq
  278. case GeCondition:
  279. return q.locateComponent(t.Field, meta), t.Value, cmpGe
  280. case GtCondition:
  281. return q.locateComponent(t.Field, meta), t.Value, cmpGt
  282. case LeCondition:
  283. return q.locateComponent(t.Field, meta), t.Value, cmpLe
  284. case LtCondition:
  285. return q.locateComponent(t.Field, meta), t.Value, cmpLt
  286. default:
  287. return -1, nil, cmpEq
  288. }
  289. }
  290. // flattenAnd 把 AND 树展平成叶子条件。
  291. // OR / NOT / LIKE / IN 不是合取项, 整体当叶子返回 —— 它们给不出索引边界,
  292. // 但必须原样保留下来做行级过滤。
  293. func flattenAnd(cond Condition, out *[]Condition) {
  294. if and, ok := cond.(AndCondition); ok {
  295. for _, sub := range and.Conditions {
  296. flattenAnd(sub, out)
  297. }
  298. return
  299. }
  300. *out = append(*out, cond)
  301. }
  302. // incBE 把 buf 当作大端无符号整数加一 (原地)。返回 false 表示溢出 ——
  303. // 此时 buf 之后不再存在任何更大的键。
  304. func incBE(buf []byte) bool {
  305. for i := len(buf) - 1; i >= 0; i-- {
  306. buf[i]++
  307. if buf[i] != 0 {
  308. return true
  309. }
  310. }
  311. return false
  312. }
  313. // fillFF 把 buf[from:] 全置 0xFF (该分量及其后分量的最大值)。
  314. // from 可以是 0 —— 首分量就是范围分量时前缀为空, 此时整个键都无上界。
  315. func fillFF(buf []byte, from int) {
  316. for i := from; i < len(buf); i++ {
  317. buf[i] = 0xFF
  318. }
  319. }
  320. // buildScanPlan 分析 WHERE 条件, 选择最优索引
  321. func (q *Query) buildScanPlan() *scanPlan {
  322. if q.whereCond == nil {
  323. return nil
  324. }
  325. if q.table.indexMeta == nil {
  326. return nil
  327. }
  328. // 先展平成合取项: 索引区间是按"分量"折叠出来的, 只有 AND 语义才可加。
  329. var leaves []Condition
  330. flattenAnd(q.whereCond, &leaves)
  331. var bestPlan *scanPlan
  332. for i := range q.table.indexMeta.metas {
  333. m := &q.table.indexMeta.metas[i]
  334. if m.Flag&0x80 != 0 {
  335. continue
  336. }
  337. // 主键索引直接承载全部行, 但它的 B+ 树叶键是 pkID, 而不是"建在哪一列上"。
  338. // planIndex 会用 meta.FieldIDs 编码出的【字段值】当扫描区间 (见 buildKeyLayout),
  339. // 拿它去比对 pkID 叶键, 语义对不上 —— 只有当该列的值恒等于 pkID 时才偶然正确,
  340. // 否则会静默地只命中/漏掉若干行 (例如 Delete/Update 的条件扫描)。
  341. // 因此主键索引不参与列条件规划, 这类查询退回全表扫描 + 行级过滤 (fullTableScan
  342. // 会施加 whereCond), 结果正确; 按 pkID 的点查/回表仍走 SearchByIndex/ResolveByPK,
  343. // 不经过这里, 不受影响。
  344. if m.IndexType == page.IndexTypePrimary {
  345. continue
  346. }
  347. handler, ok := index.Compose.GetHandler(m.IndexType)
  348. if !ok {
  349. continue
  350. }
  351. plan := q.planIndex(m, handler, leaves)
  352. if plan == nil {
  353. continue // 此索引不匹配
  354. }
  355. // 该索引是否承载行数据: 由处理器自报, 本层不认识索引类型
  356. plan.rowStore = handler.IsRowStore()
  357. if plan.rowStore {
  358. return plan // 行存储索引最优 (免回表), 不再找
  359. }
  360. if bestPlan == nil {
  361. bestPlan = plan
  362. }
  363. }
  364. return bestPlan
  365. }
  366. // planIndex 为一个索引推导扫描区间; 该索引用不上时返回 nil。
  367. func (q *Query) planIndex(m *IndexMeta, handler index.IndexHandler, leaves []Condition) *scanPlan {
  368. lay, ok := q.buildKeyLayout(m)
  369. if !ok {
  370. return nil
  371. }
  372. n := len(lay.sizes)
  373. cons := make([]keyConstraint, n) // 各分量合并后的边界
  374. compCond := make([][]Condition, n) // 各分量上的原始条件 (用于决定哪些能丢)
  375. var rest []Condition // 与索引无关、必须保留的条件
  376. for _, c := range leaves {
  377. k, value, kind := q.classifyLeaf(c, m)
  378. if k < 0 {
  379. rest = append(rest, c)
  380. continue
  381. }
  382. ft := q.table.Field[m.FieldIDs[k]].FieldType
  383. // 用 Safe 版本: 条件的值类型与列存储类型不符时 encodeIndexKey 会 panic,
  384. // 规划阶段不该把用户输入直接变成崩溃 —— 退回行级过滤由 Match 去处理。
  385. // 带上列级 param (decimal 的 scale / 字符串的宽度码): 索引键必须与行内字节完全一致。
  386. enc, err := encodeIndexKeySafeWithParam(value, ft, q.table.fieldParam(int(m.FieldIDs[k])))
  387. if err != nil || len(enc) != lay.sizes[k] {
  388. // 编码失败, 或长度与分量长度不符 (拼进定长键会错位) → 交给行级过滤
  389. rest = append(rest, c)
  390. continue
  391. }
  392. if !cons[k].add(kind, enc) {
  393. // 该分量上的条件互相矛盾 → 结果必为空。
  394. // 这里保守地"放弃索引"而不是返回空区间: 定长补码编码下负数字节序与
  395. // 数值序相反, 用字节比较断定"空"对负数不成立, 退回全表扫描更稳。
  396. return nil
  397. }
  398. compCond[k] = append(compCond[k], c)
  399. }
  400. if cons[0].count == 0 {
  401. return nil // 首分量没有边界 → 索引给不出连续区间
  402. }
  403. // 从左往右消费"等值分量"; 之后最多再消费一个范围分量, 更后面的分量帮不上忙。
  404. eqLen := 0
  405. for eqLen < n && cons[eqLen].isEquality() {
  406. eqLen++
  407. }
  408. rangeIdx := -1
  409. if eqLen < n && cons[eqLen].count > 0 {
  410. rangeIdx = eqLen
  411. }
  412. startKey := make([]byte, lay.total)
  413. endKey := make([]byte, lay.total)
  414. prefix := 0
  415. for j := 0; j < eqLen; j++ {
  416. copy(startKey[prefix:], cons[j].lo)
  417. copy(endKey[prefix:], cons[j].lo)
  418. prefix += len(cons[j].lo)
  419. }
  420. plan := &scanPlan{
  421. meta: m, handler: handler,
  422. startKey: startKey, endKey: endKey,
  423. startInclusive: true, endInclusive: true,
  424. remainingCond: q.remainCond(rest, compCond, eqLen, rangeIdx),
  425. }
  426. // 全部等值 → 精确键 (此时 prefix == total, fillFF 无事可做);
  427. // 只消费了等值前缀 → 该前缀下的全部键: [前缀||00.., 前缀||FF..]。
  428. if eqLen == n || rangeIdx < 0 {
  429. fillFF(endKey, prefix)
  430. return plan
  431. }
  432. rc := &cons[rangeIdx]
  433. size := lay.sizes[rangeIdx]
  434. // 下界: [前缀 || 分量值 || 00..]
  435. if rc.lo != nil {
  436. copy(startKey[prefix:], rc.lo)
  437. if !rc.loInc {
  438. // 严格下界: 要跳过分量 == lo 的全部键, 即把 (前缀||lo) 整体加一
  439. if !incBE(startKey[:prefix+size]) {
  440. return nil // 已经是最大键, 该条件不可能有匹配行
  441. }
  442. }
  443. }
  444. // 上界: [前缀 || 分量值 || FF..]
  445. if rc.hi == nil {
  446. fillFF(endKey, prefix)
  447. } else if rc.hiInc {
  448. copy(endKey[prefix:], rc.hi)
  449. fillFF(endKey, prefix+size)
  450. } else {
  451. // 严格上界: 分量 == hi 的键全部排除
  452. copy(endKey[prefix:], rc.hi)
  453. plan.endInclusive = false
  454. }
  455. return plan
  456. }
  457. // remainCond 汇总索引区间没能表达、仍需逐行过滤的条件。
  458. // 已被区间精确覆盖的分量 (等值前缀 + 那个范围分量) 上的条件可以安全丢掉。
  459. func (q *Query) remainCond(rest []Condition, compCond [][]Condition, eqLen, rangeIdx int) Condition {
  460. remaining := rest
  461. for j := range compCond {
  462. if j < eqLen || j == rangeIdx {
  463. continue
  464. }
  465. remaining = append(remaining, compCond[j]...)
  466. }
  467. switch len(remaining) {
  468. case 0:
  469. return nil
  470. case 1:
  471. return remaining[0]
  472. default:
  473. return And(remaining...)
  474. }
  475. }
  476. // rowWithPK 把结果行与它的 pkID 绑在一起 —— 排序/翻页会重排结果集, pkID 必须
  477. // 跟着行一起移动, 否则回调会把 A 行的 pkID 配到 B 行的数据上。
  478. type rowWithPK struct {
  479. pkID uint64
  480. row []types.FieldValue
  481. }
  482. // compareRowsForOrderBy 按 OrderBy 规则比较两行, 返回 -1/0/1。
  483. // 0 表示"所有排序列都无法区分"(字段缺失), 由调用方用稳定排序保持原顺序。
  484. func (q *Query) compareRowsForOrderBy(a, b []types.FieldValue) int {
  485. for _, ob := range q.orderBys {
  486. idx := q.table.findFieldIndex(ob.Field)
  487. if idx < 0 {
  488. continue
  489. }
  490. vi := findFieldValue(a, ob.Field)
  491. vj := findFieldValue(b, ob.Field)
  492. if vi == nil || vj == nil {
  493. continue
  494. }
  495. cmp := compareFieldValues(vi, vj, q.table.Field[idx].FieldType)
  496. if cmp == 0 {
  497. continue
  498. }
  499. if ob.Descending {
  500. return -cmp
  501. }
  502. return cmp
  503. }
  504. return 0
  505. }
  506. // ======================== 核心查询 ========================
  507. // Find 执行查询,返回多行
  508. func (q *Query) Find() ([][]types.FieldValue, error) {
  509. var results [][]types.FieldValue
  510. err := q.scan(func(row []types.FieldValue) bool {
  511. results = append(results, row)
  512. return true
  513. })
  514. if err != nil {
  515. return nil, err
  516. }
  517. // 投影
  518. if len(q.selectCols) > 0 {
  519. results = q.project(results)
  520. }
  521. return results, nil
  522. }
  523. // Scan 流式扫描查询, 回调函数逐行处理数据, 返回 false 提前终止
  524. // 适用于不需要全量收集结果的场景, 内存友好
  525. func (q *Query) Scan(callback func(row []types.FieldValue) bool) error {
  526. return q.scan(callback)
  527. }
  528. // scan 内部流式扫描核心方法
  529. // 自动处理: 索引选择 → 排序 → OFFSET → LIMIT → 回调
  530. func (q *Query) scan(callback func(row []types.FieldValue) bool) error {
  531. return q.scanWithPKID(func(_ uint64, row []types.FieldValue) bool {
  532. return callback(row)
  533. })
  534. }
  535. // ScanWithPKID 流式扫描, 回调同时拿到行主键号 pkID 与列值。
  536. //
  537. // 迁移/导出工具必须用这个而不是 Scan: 行数据里不含 pkID (它是行的 8 字节前缀,
  538. // 不是字段), 只拿字段值就没法还原"这一行的主键号是多少" —— 导出到 SQL 时要么
  539. // 丢掉真实主键, 要么被迫用某个列值冒充 (列值可能是 0、可能被改过)。
  540. func (q *Query) ScanWithPKID(callback func(pkID uint64, row []types.FieldValue) bool) error {
  541. return q.scanWithPKID(callback)
  542. }
  543. // scanWithPKID 与 scan 完全一致, 但额外把每行的真实 pkID 交给回调。
  544. //
  545. // 为什么需要: 行数据里不含 pkID (它是行的 8 字节前缀, 不是字段), 普通 Scan 回调
  546. // 只拿得到字段值。删除/更新必须按真实 pkID 定位行, 旧实现只能退而求其次地
  547. // "取第一个 uint64 类型的字段值当 pkID" —— 主键列不是行内第一个 8 字节列时,
  548. // 它删掉的是另一个主键指向的行, 匹配上的行反而一条都没动, 而且不报错。
  549. func (q *Query) scanWithPKID(callback func(pkID uint64, row []types.FieldValue) bool) error {
  550. plan := q.buildScanPlan()
  551. // 判断是否需要内存排序 (OrderBy 字段与索引不一致时)
  552. needSort := false
  553. if len(q.orderBys) > 0 {
  554. if plan == nil {
  555. needSort = true
  556. } else {
  557. idxField := q.fieldNameFromMeta(plan.meta)
  558. if !(len(q.orderBys) == 1 && q.orderBys[0].Field == idxField) {
  559. needSort = true
  560. }
  561. }
  562. }
  563. // 需要排序时, 必须先收集全部再排序, 无法流式 LIMIT
  564. if needSort {
  565. var all []rowWithPK
  566. err := q.executeScan(func(pkID uint64, row []types.FieldValue) bool {
  567. all = append(all, rowWithPK{pkID, row})
  568. return true
  569. }, plan)
  570. if err != nil {
  571. return err
  572. }
  573. // 排序必须连 pkID 一起搬: 只排 []FieldValue 会让回调拿到错位的 pkID
  574. sort.SliceStable(all, func(i, j int) bool {
  575. return q.compareRowsForOrderBy(all[i].row, all[j].row) < 0
  576. })
  577. // OFFSET
  578. if q.offset > 0 {
  579. if q.offset >= len(all) {
  580. return nil
  581. }
  582. all = all[q.offset:]
  583. }
  584. // LIMIT
  585. if q.limit > 0 && q.limit < len(all) {
  586. all = all[:q.limit]
  587. }
  588. for _, item := range all {
  589. if !callback(item.pkID, item.row) {
  590. return nil
  591. }
  592. }
  593. return nil
  594. }
  595. // 不需要排序: 直接流式传递 callback, 支持 LIMIT 提前终止
  596. seen := 0
  597. return q.executeScan(func(pkID uint64, row []types.FieldValue) bool {
  598. if seen < q.offset {
  599. seen++
  600. return true // 跳过 OFFSET
  601. }
  602. seen++
  603. if !callback(pkID, row) {
  604. return false // 用户要求停止
  605. }
  606. // LIMIT 检查 (0 表示无限制)
  607. if q.limit > 0 && seen-q.offset >= q.limit {
  608. return false // 已满足, 提前终止扫描
  609. }
  610. return true
  611. }, plan)
  612. }
  613. // executeScan 执行索引扫描或全表扫描, 将反序列化后的行传递给回调
  614. func (q *Query) executeScan(callback func(pkID uint64, row []types.FieldValue) bool, plan *scanPlan) error {
  615. if plan != nil {
  616. return q.indexScan(plan, callback)
  617. }
  618. return q.fullTableScan(callback)
  619. }
  620. // indexScan 使用索引扫描并按"先物化、后回表"两阶段执行。
  621. //
  622. // 为什么不能像旧实现那样在 RangeScan 回调里直接回表 + 触发用户 callback:
  623. // RangeScan 是沿叶子双向链 (PageHdr.NextPage) 推进的裸游标, 而用户的 Scan 回调
  624. // 常常会对【同一棵索引】做 Update/Delete —— 删旧条目 + 插新条目会触发叶分裂/合并,
  625. // 被合并掉的叶子页会被登记回收, 下一个 Commit/drain 时该页被清零并改写成空闲链节点
  626. // (空闲链同样用 PageHdr.NextPage 串接)。此时游标再读该页的 NextPage, 拿到的就是
  627. // 空闲链指针, 于是跳到一张 type=0 的空页上 (实测 panic: bad page type=0)。
  628. //
  629. // 物化把"遍历"与"修改"彻底分开: 遍历阶段树保持只读, 游标始终有效; 修改发生在
  630. // 遍历结束之后, 不再影响游标。二级索引只物化 pkID(8B/行), 内存开销与结果集成正比
  631. // 且远小于整行物化; rowStore 索引物化的是行的快照 (必须拷贝, 因为它是页内缓冲视图)。
  632. func (q *Query) indexScan(plan *scanPlan, callback func(pkID uint64, row []types.FieldValue) bool) error {
  633. // 判断 OrderBy 是否需要反向
  634. reverse := false
  635. if len(q.orderBys) == 1 {
  636. idxField := q.fieldNameFromMeta(plan.meta)
  637. if q.orderBys[0].Field == idxField && q.orderBys[0].Descending {
  638. reverse = true
  639. }
  640. }
  641. if plan.rowStore {
  642. // 承载行数据的索引: RangeScan 返回 storeRow = [pkID(8B) + rowData]。
  643. // storeRow 指向页缓冲, 遍历结束后页可能被回收改写, 必须拷贝一份快照。
  644. var rows [][]byte
  645. if err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  646. plan.startKey, plan.endKey, plan.startInclusive, plan.endInclusive, reverse,
  647. func(row []byte) bool {
  648. if len(row) < 8 {
  649. return true
  650. }
  651. snapshot := make([]byte, len(row))
  652. copy(snapshot, row)
  653. rows = append(rows, snapshot)
  654. return true
  655. }); err != nil {
  656. return err
  657. }
  658. for _, row := range rows {
  659. rowData := row[8:]
  660. if plan.remainingCond != nil {
  661. if !plan.remainingCond.Match(rowData, q.table) {
  662. continue
  663. }
  664. }
  665. if !callback(binary.BigEndian.Uint64(row[:8]), q.table.deserializeRow(rowData)) {
  666. return nil
  667. }
  668. }
  669. return nil
  670. }
  671. // 二级索引: RangeScan 返回 pkID(8B BE)。只按顺序物化 pkID, 回表放到遍历之后。
  672. var pkIDs []uint64
  673. if err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  674. plan.startKey, plan.endKey, plan.startInclusive, plan.endInclusive, reverse,
  675. func(row []byte) bool {
  676. if len(row) < 8 {
  677. return true
  678. }
  679. pkIDs = append(pkIDs, binary.BigEndian.Uint64(row[:8]))
  680. return true
  681. }); err != nil {
  682. return err
  683. }
  684. for _, pkID := range pkIDs {
  685. storeRow, found := q.table.indexMeta.ResolveByPK(pkID)
  686. if !found {
  687. // 行已被之前的回调删除, 跳过
  688. continue
  689. }
  690. rowData := storeRow[8:]
  691. if plan.remainingCond != nil {
  692. if !plan.remainingCond.Match(rowData, q.table) {
  693. continue
  694. }
  695. }
  696. if !callback(pkID, q.table.deserializeRow(rowData)) {
  697. return nil
  698. }
  699. }
  700. return nil
  701. }
  702. // fullTableScan 全表扫描 (流式回调模式)
  703. func (q *Query) fullTableScan(callback func(pkID uint64, row []types.FieldValue) bool) error {
  704. // 找承载行数据的索引 (由处理器自报, 本层不认识索引类型)
  705. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  706. if !ok || primMeta == nil || primHandler == nil {
  707. return nil
  708. }
  709. dpIDs := primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage)
  710. for _, dpID := range dpIDs {
  711. rows := primHandler.ReadDataPageRows(q.table.handle, dpID)
  712. for _, storeRow := range rows {
  713. if len(storeRow) < 8 {
  714. continue
  715. }
  716. rowData := storeRow[8:]
  717. if q.whereCond != nil {
  718. if !q.whereCond.Match(rowData, q.table) {
  719. continue
  720. }
  721. }
  722. if !callback(binary.BigEndian.Uint64(storeRow[:8]), q.table.deserializeRow(rowData)) {
  723. return nil // 回调要求提前终止
  724. }
  725. }
  726. }
  727. return nil
  728. }
  729. // ======================== 裸字节扫描 (聚合专用) ========================
  730. // scanRaw 裸字节版流式扫描: 回调拿 (pkID, 原始行字节), 全程不 deserializeRow。
  731. //
  732. // 背景: Count/Sum/Max/Min 每行只需要"过条件 + 最多一列", 而 scan 管线对每行都
  733. // 分配 []FieldValue 并解码全部活跃列 —— 100 万行的 SUM 里这部分占了绝对大头
  734. // (实测带条件全表扫描每行 ~0.66µs, 整行物化路径 ~1.4µs/行)。
  735. //
  736. // 约束: 只服务内部只读聚合。有 ORDER BY 时排序要比较解码后的列值, 这条路径
  737. // 无能为力 —— 调用方必须先退回整行路径。OFFSET/LIMIT 语义与 scanWithPKID
  738. // 的无排序分支逐行一致。
  739. func (q *Query) scanRaw(callback func(pkID uint64, rowData []byte) bool) error {
  740. plan := q.buildScanPlan()
  741. seen := 0
  742. return q.executeScanRaw(func(pkID uint64, rowData []byte) bool {
  743. if seen < q.offset {
  744. seen++
  745. return true // 跳过 OFFSET
  746. }
  747. seen++
  748. if !callback(pkID, rowData) {
  749. return false // 用户要求停止
  750. }
  751. if q.limit > 0 && seen-q.offset >= q.limit {
  752. return false // 已满足 LIMIT, 提前终止扫描
  753. }
  754. return true
  755. }, plan)
  756. }
  757. func (q *Query) executeScanRaw(callback func(pkID uint64, rowData []byte) bool, plan *scanPlan) error {
  758. if plan != nil {
  759. return q.indexScanRaw(plan, callback)
  760. }
  761. return q.fullTableScanRaw(callback)
  762. }
  763. // indexScanRaw 与 indexScan 走同一执行计划, 但回调拿裸行字节, 且遍历中同步回表。
  764. //
  765. // 为什么可以在 RangeScan 回调里直接回表 (indexScan 却必须"先物化、后回表"):
  766. // 物化两阶段是为"用户回调会在遍历中 Update/Delete 同一棵索引"准备的 —— 叶分裂/
  767. // 合并会让裸游标读到被改写的页。本路径的消费者全是只读聚合, 遍历中不存在任何
  768. // 写操作, 游标必然有效; 于是物化 (含 rowStore 的逐行快照拷贝) 一并省掉。
  769. func (q *Query) indexScanRaw(plan *scanPlan, callback func(pkID uint64, rowData []byte) bool) error {
  770. if plan.rowStore {
  771. // 承载行数据的索引: 条目即 storeRow = [pkID(8B) + rowData]
  772. return plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  773. plan.startKey, plan.endKey, plan.startInclusive, plan.endInclusive, false,
  774. func(row []byte) bool {
  775. if len(row) < 8 {
  776. return true
  777. }
  778. rowData := row[8:]
  779. if plan.remainingCond != nil && !plan.remainingCond.Match(rowData, q.table) {
  780. return true
  781. }
  782. return callback(binary.BigEndian.Uint64(row[:8]), rowData)
  783. })
  784. }
  785. // 二级索引: 条目 = pkID(8B BE), 遍历中同步回表 (只读, 不触碰被遍历的索引结构)
  786. return plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  787. plan.startKey, plan.endKey, plan.startInclusive, plan.endInclusive, false,
  788. func(row []byte) bool {
  789. if len(row) < 8 {
  790. return true
  791. }
  792. storeRow, found := q.table.indexMeta.ResolveByPK(binary.BigEndian.Uint64(row[:8]))
  793. if !found {
  794. return true // 行已被删除, 跳过
  795. }
  796. rowData := storeRow[8:]
  797. if plan.remainingCond != nil && !plan.remainingCond.Match(rowData, q.table) {
  798. return true
  799. }
  800. return callback(binary.BigEndian.Uint64(row[:8]), rowData)
  801. })
  802. }
  803. // fullTableScanRaw 与 fullTableScan 同构, 回调拿裸行字节。
  804. // ReadDataPageRows 返回的行本就是拷贝快照, rowData 跨回调安全。
  805. func (q *Query) fullTableScanRaw(callback func(pkID uint64, rowData []byte) bool) error {
  806. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  807. if !ok || primMeta == nil || primHandler == nil {
  808. return nil
  809. }
  810. dpIDs := primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage)
  811. for _, dpID := range dpIDs {
  812. for _, storeRow := range primHandler.ReadDataPageRows(q.table.handle, dpID) {
  813. if len(storeRow) < 8 {
  814. continue
  815. }
  816. rowData := storeRow[8:]
  817. if q.whereCond != nil {
  818. if !q.whereCond.Match(rowData, q.table) {
  819. continue
  820. }
  821. }
  822. if !callback(binary.BigEndian.Uint64(storeRow[:8]), rowData) {
  823. return nil // 回调要求提前终止
  824. }
  825. }
  826. }
  827. return nil
  828. }
  829. // ======================== 排序 ========================
  830. func (q *Query) sortResults(results [][]types.FieldValue) {
  831. sort.SliceStable(results, func(i, j int) bool {
  832. return q.compareRowsForOrderBy(results[i], results[j]) < 0
  833. })
  834. }
  835. func findFieldValue(row []types.FieldValue, field string) interface{} {
  836. for _, fv := range row {
  837. if string(fv.FieldName) == field {
  838. return fv.Value
  839. }
  840. }
  841. return nil
  842. }
  843. // cmpInt64 / cmpUint64 把三态比较收敛到一处, 避免每个分支重复写一遍 if 链。
  844. func cmpInt64(a, b int64) int {
  845. switch {
  846. case a < b:
  847. return -1
  848. case a > b:
  849. return 1
  850. }
  851. return 0
  852. }
  853. func cmpUint64(a, b uint64) int {
  854. switch {
  855. case a < b:
  856. return -1
  857. case a > b:
  858. return 1
  859. }
  860. return 0
  861. }
  862. // compareFieldValues 按【字段类型】比较同一列的两个值, 返回 -1/0/1。
  863. //
  864. // 类型必须由调用方传入, 不能只看 Go 值类型: 同一列都可能读成 int16, 但它既可能来自
  865. // 有符号的 FieldType_Int16 (int16 语义), 也可能来自无符号的 FieldType_Uint16 ——
  866. // 后者的值是 uint16 的位模式被重解释成 int16, 两者序不同 (位模式 0xFFFF: int16 是 -1,
  867. // uint16 是 65535)。旧实现只按 Go 值类型分派, 既分不清这两种, 又整个漏掉了 int8/int64。
  868. //
  869. // 有符号类型比的是【解码后的值】而不是盘上字节: 盘上是保序编码 (符号位已翻转),
  870. // 直接比字节也对, 但这里拿到的是已解码的值, 比数值更直白。
  871. func compareFieldValues(a, b interface{}, ft types.FieldType) int {
  872. switch ft {
  873. case types.FieldType_Int8:
  874. return cmpInt64(int64(a.(int8)), int64(b.(int8)))
  875. case types.FieldType_Int16:
  876. return cmpInt64(int64(a.(int16)), int64(b.(int16)))
  877. case types.FieldType_Int32:
  878. return cmpInt64(int64(a.(int32)), int64(b.(int32)))
  879. case types.FieldType_Int64:
  880. return cmpInt64(a.(int64), b.(int64))
  881. case types.FieldType_Uint8:
  882. return cmpUint64(uint64(a.(byte)), uint64(b.(byte)))
  883. case types.FieldType_Uint16:
  884. // 无符号: 先把 int16 位模式还原回 uint16 再比, 否则 > 32767 的值会被当成负数
  885. return cmpUint64(uint64(uint16(a.(int16))), uint64(uint16(b.(int16))))
  886. case types.FieldType_Uint32:
  887. return cmpUint64(uint64(uint32(a.(int32))), uint64(uint32(b.(int32))))
  888. case types.FieldType_Uint64:
  889. return cmpUint64(a.(uint64), b.(uint64))
  890. case types.FieldType_Float64:
  891. // 同一列读出的一定是同一类型, 故 b 也是 float64; 容错地走 toFloat64
  892. fa, fb := toFloat64(a), toFloat64(b)
  893. switch {
  894. case fa < fb:
  895. return -1
  896. case fa > fb:
  897. return 1
  898. }
  899. return 0
  900. case types.FieldType_Float32:
  901. fa, fb := a.(float32), b.(float32)
  902. switch {
  903. case fa < fb:
  904. return -1
  905. case fa > fb:
  906. return 1
  907. }
  908. return 0
  909. case types.FieldType_Bool:
  910. // false < true (与盘上 0x00 < 0x01 的字节序一致)
  911. ba, bb := a.(bool), b.(bool)
  912. switch {
  913. case ba == bb:
  914. return 0
  915. case !ba:
  916. return -1
  917. }
  918. return 1
  919. case types.FieldType_Year:
  920. // 同 uint16: 载体是 int16, 但语义是无符号年份
  921. return cmpUint64(uint64(uint16(a.(int16))), uint64(uint16(b.(int16))))
  922. case types.FieldType_Decimal:
  923. // 走数值比较 (自动对齐 scale): 同一列的 scale 必然相同, 但比较函数不该依赖这一点
  924. return a.(types.Decimal).Cmp(b.(types.Decimal))
  925. case types.FieldType_Int128:
  926. na, oka := a.(*big.Int)
  927. nb, okb := b.(*big.Int)
  928. if !oka || !okb {
  929. return 0
  930. }
  931. return na.Cmp(nb)
  932. case types.FieldType_UUID:
  933. ua, oka := a.(types.UUID)
  934. ub, okb := b.(types.UUID)
  935. if !oka || !okb {
  936. return 0
  937. }
  938. return bytes.Compare(ua[:], ub[:])
  939. }
  940. // 动态字段与所有定长字符串: 按字节序
  941. ba, ok := a.([]byte)
  942. if !ok {
  943. return 0
  944. }
  945. bb, ok := b.([]byte)
  946. if !ok {
  947. return 0
  948. }
  949. return bytes.Compare(ba, bb)
  950. }
  951. // fieldTypeOf 取某列的存储类型, 供按类型比较/聚合使用; 列不存在时返回 0。
  952. func (q *Query) fieldTypeOf(name string) types.FieldType {
  953. if i := q.table.findFieldIndex(name); i >= 0 {
  954. return q.table.Field[i].FieldType
  955. }
  956. return 0
  957. }
  958. // ======================== 投影 ========================
  959. func (q *Query) project(results [][]types.FieldValue) [][]types.FieldValue {
  960. colSet := make(map[string]bool)
  961. for _, c := range q.selectCols {
  962. colSet[c] = true
  963. }
  964. for i, row := range results {
  965. var filtered []types.FieldValue
  966. for _, fv := range row {
  967. if colSet[string(fv.FieldName)] {
  968. filtered = append(filtered, fv)
  969. }
  970. }
  971. results[i] = filtered
  972. }
  973. return results
  974. }
  975. // ======================== 流式聚合 ========================
  976. // FindOne 流式查询,返回单行 (命中即停,不遍历全表)
  977. func (q *Query) FindOne() ([]types.FieldValue, error) {
  978. var result []types.FieldValue
  979. found := false
  980. err := q.scan(func(row []types.FieldValue) bool {
  981. result = row
  982. found = true
  983. return false // 找到第一行即停止
  984. })
  985. if err != nil {
  986. return nil, err
  987. }
  988. if !found {
  989. return nil, page.ErrNotFound
  990. }
  991. return result, nil
  992. }
  993. // Count 流式计数。
  994. //
  995. // 三级加速 (每级都严格保持与全量扫描相同的计数语义):
  996. // 1. 无条件无分页排序 → 逐页数活行 (DataPage::CountLiveRows), 不物化、不解码;
  997. // 2. WHERE 被索引区间完全消费 (remainingCond == nil) → 直接数索引条目,
  998. // 不回表、不反序列化 —— 旧实现这里每个命中行都做一次 ResolveByPK +
  999. // deserializeRow, "用索引 COUNT" 反而比全表扫描更慢 (20k 行 632ms);
  1000. // 3. 其余 → 裸字节扫描计数 (deserializeField 都不需要)。
  1001. // 带 OFFSET/LIMIT/ORDER BY 时保持旧行为 (旧实现的 Count 语义上会先被分页截断)。
  1002. func (q *Query) Count() (int64, error) {
  1003. paged := q.limit > 0 || q.offset > 0 || len(q.orderBys) > 0
  1004. if !paged && q.whereCond == nil {
  1005. return q.countAllLive(), nil
  1006. }
  1007. if !paged {
  1008. if plan := q.buildScanPlan(); plan != nil && plan.remainingCond == nil {
  1009. var count int64
  1010. err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  1011. plan.startKey, plan.endKey, plan.startInclusive, plan.endInclusive, false,
  1012. func(row []byte) bool {
  1013. if len(row) >= 8 {
  1014. count++
  1015. }
  1016. return true
  1017. })
  1018. return count, err
  1019. }
  1020. var count int64
  1021. err := q.scanRaw(func(_ uint64, _ []byte) bool {
  1022. count++
  1023. return true
  1024. })
  1025. return count, err
  1026. }
  1027. var count int64
  1028. err := q.scan(func(row []types.FieldValue) bool {
  1029. count++
  1030. return true
  1031. })
  1032. return count, err
  1033. }
  1034. // countAllLive 逐页累加活行数 (无条件 COUNT(*) 的 O(页数) 路径)。
  1035. func (q *Query) countAllLive() int64 {
  1036. if q.table.indexMeta == nil {
  1037. return 0
  1038. }
  1039. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  1040. if !ok || primMeta == nil || primHandler == nil {
  1041. return 0
  1042. }
  1043. // 处理器实现了免物化计数就用它; 否则退回"读全部行再取 len"
  1044. type liveCounter interface {
  1045. ReadDataPageLiveCount(handle page.HandleDb, dpID uint32) int
  1046. }
  1047. counter, canCount := primHandler.(liveCounter)
  1048. var total int64
  1049. for _, dpID := range primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage) {
  1050. if canCount {
  1051. total += int64(counter.ReadDataPageLiveCount(q.table.handle, dpID))
  1052. continue
  1053. }
  1054. total += int64(len(primHandler.ReadDataPageRows(q.table.handle, dpID)))
  1055. }
  1056. return total
  1057. }
  1058. // Sum 流式求和。
  1059. // 每行只解码目标一列 (Table.deserializeField), 不再物化整行; 带 ORDER BY 时
  1060. // 排序管线需要整行, 保持旧路径。条件过滤 (whereCond/remainingCond) 在裸字节上
  1061. // 进行, 与旧路径同一套 Match。
  1062. func (q *Query) Sum(col string) (float64, error) {
  1063. if len(q.orderBys) > 0 {
  1064. var sum float64
  1065. err := q.scan(func(row []types.FieldValue) bool {
  1066. for _, fv := range row {
  1067. if string(fv.FieldName) == col {
  1068. sum += toFloat64(fv.Value)
  1069. break
  1070. }
  1071. }
  1072. return true
  1073. })
  1074. return sum, err
  1075. }
  1076. var sum float64
  1077. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1078. if v, ok := q.table.deserializeField(rowData, col); ok {
  1079. sum += toFloat64(v)
  1080. }
  1081. return true
  1082. })
  1083. return sum, err
  1084. }
  1085. // Max 流式求最大值。
  1086. //
  1087. // 加速分两档:
  1088. // 1. 目标列是某二级索引首列且无 WHERE/分页/排序 → 直接取索引端点
  1089. // (反向 RangeScan 第一条即最大键), O(log N) —— 旧实现对 100 万行
  1090. // 线性扫 1.4s, MySQL/SQLite 同场景是 2.6ms/45µs;
  1091. // 2. 其余 → 裸字节扫描, 每行只解码目标一列。
  1092. func (q *Query) Max(col string) (interface{}, error) {
  1093. if v, hit, err := q.minMaxViaIndex(col, true); hit || err != nil {
  1094. return v, err
  1095. }
  1096. ft := q.fieldTypeOf(col)
  1097. if len(q.orderBys) > 0 {
  1098. var maxVal interface{}
  1099. err := q.scan(func(row []types.FieldValue) bool {
  1100. for _, fv := range row {
  1101. if string(fv.FieldName) == col {
  1102. if maxVal == nil || compareFieldValues(fv.Value, maxVal, ft) > 0 {
  1103. maxVal = fv.Value
  1104. }
  1105. break
  1106. }
  1107. }
  1108. return true
  1109. })
  1110. return maxVal, err
  1111. }
  1112. var maxVal interface{}
  1113. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1114. if v, ok := q.table.deserializeField(rowData, col); ok {
  1115. if maxVal == nil || compareFieldValues(v, maxVal, ft) > 0 {
  1116. maxVal = v
  1117. }
  1118. }
  1119. return true
  1120. })
  1121. return maxVal, err
  1122. }
  1123. // Min 流式求最小值 (加速路径同 Max, 端点取正向第一条)。
  1124. func (q *Query) Min(col string) (interface{}, error) {
  1125. if v, hit, err := q.minMaxViaIndex(col, false); hit || err != nil {
  1126. return v, err
  1127. }
  1128. ft := q.fieldTypeOf(col)
  1129. if len(q.orderBys) > 0 {
  1130. var minVal interface{}
  1131. err := q.scan(func(row []types.FieldValue) bool {
  1132. for _, fv := range row {
  1133. if string(fv.FieldName) == col {
  1134. if minVal == nil || compareFieldValues(fv.Value, minVal, ft) < 0 {
  1135. minVal = fv.Value
  1136. }
  1137. break
  1138. }
  1139. }
  1140. return true
  1141. })
  1142. return minVal, err
  1143. }
  1144. var minVal interface{}
  1145. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1146. if v, ok := q.table.deserializeField(rowData, col); ok {
  1147. if minVal == nil || compareFieldValues(v, minVal, ft) < 0 {
  1148. minVal = v
  1149. }
  1150. }
  1151. return true
  1152. })
  1153. return minVal, err
  1154. }
  1155. // minMaxViaIndex 取索引端点求 Max/Min。
  1156. //
  1157. // 前提: 目标列是某个二级索引的首列, 且查询不带 WHERE/分页/排序 —— 此时
  1158. // "全表最大值"就是"该索引里最大的键" (索引键编码与行内字节同源, 字节序即值序,
  1159. // 见 encodeIndexKey 的说明), 反向 (Max) / 正向 (Min) RangeScan 的第一条即答案。
  1160. // 回调返回 false 提前终止遍历, 成本只有一次树下降。
  1161. //
  1162. // 返回 (值, 是否命中快速路径, err); 未命中时调用方走全扫路径。
  1163. func (q *Query) minMaxViaIndex(col string, wantMax bool) (interface{}, bool, error) {
  1164. if q.whereCond != nil || q.limit > 0 || q.offset > 0 || len(q.orderBys) > 0 {
  1165. return nil, false, nil
  1166. }
  1167. if q.table.indexMeta == nil {
  1168. return nil, false, nil
  1169. }
  1170. for i := range q.table.indexMeta.metas {
  1171. m := &q.table.indexMeta.metas[i]
  1172. if m.Flag&0x80 != 0 || m.IndexType == page.IndexTypePrimary {
  1173. continue
  1174. }
  1175. if q.fieldNameFromMeta(m) != col {
  1176. continue
  1177. }
  1178. if _, ok := q.buildKeyLayout(m); !ok {
  1179. continue // 索引当前不可用 (列被删 / 动态列), 退回全扫
  1180. }
  1181. handler, ok := index.Compose.GetHandler(m.IndexType)
  1182. if !ok {
  1183. continue
  1184. }
  1185. var (
  1186. got interface{}
  1187. found bool
  1188. )
  1189. err := handler.RangeScan(q.table.handle, m.EntryPage,
  1190. nil, nil, true, true, wantMax,
  1191. func(row []byte) bool {
  1192. if len(row) < 8 {
  1193. return true
  1194. }
  1195. storeRow, ok := q.table.indexMeta.ResolveByPK(binary.BigEndian.Uint64(row[:8]))
  1196. if !ok {
  1197. return true // 端点条目解不出行: 索引端点不可信, 由外层退回全扫
  1198. }
  1199. if v, ok := q.table.deserializeField(storeRow[8:], col); ok {
  1200. got, found = v, true
  1201. }
  1202. return false // 只取端点一条
  1203. })
  1204. if err != nil || !found {
  1205. return nil, false, err
  1206. }
  1207. return got, true, nil
  1208. }
  1209. return nil, false, nil
  1210. }
  1211. func toFloat64(v interface{}) float64 {
  1212. switch val := v.(type) {
  1213. case float64:
  1214. return val
  1215. case float32:
  1216. return float64(val)
  1217. case uint64:
  1218. return float64(val)
  1219. case int64:
  1220. return float64(val)
  1221. case int:
  1222. return float64(val)
  1223. case int8:
  1224. return float64(val)
  1225. case int16:
  1226. return float64(val)
  1227. case int32:
  1228. return float64(val)
  1229. case byte:
  1230. return float64(val)
  1231. case bool:
  1232. if val {
  1233. return 1
  1234. }
  1235. return 0
  1236. case types.Decimal:
  1237. // 近似: decimal → float64 会失真, 但 Sum/Avg 的返回值类型就是 float64。
  1238. // 需要精确求和的金额场景请用 Decimal.Add 自行累加。
  1239. return val.Float64()
  1240. case *big.Int:
  1241. if val == nil {
  1242. return 0
  1243. }
  1244. f, _ := new(big.Float).SetInt(val).Float64()
  1245. return f
  1246. }
  1247. return 0
  1248. }