上万条数据, 短时间内连续查询几千次, 是数据库查, 还是内存查更好一点?

249 天前
 bthulu

客户库存有一万多, 要将这一万多库存按客户要求分散到几百个工位上, 需要针对库存的多个属性进行多次查询, 循环里套循环, 能查上千次甚至更多.

这种情况下, 我是直接数据库查, 还是将数据一次全拉到内存, 在内存里查更好?

数据库查可以走索引, 内存里可就没索引查一次就是全量遍历一次了. 如果有内存里支持索引的列表就好了. 语言是.net8.

别说什么优化查询方案一次查询搞定的了, 这不可能. 现实业务就是各个工位之间关系也是错综复杂, 只能这样查了.

9169 次点击
所在节点    数据库
76 条回复
22092
249 天前
你提到是 mysql 做定时任务, 可以直接 Stored Procedure + Scheduled Jobs 做, 准时高效(mysql,sqllite 可以啟用内存模式)
想自由更改而用 NET8 的 可以将数据一次全拉到内存(用 ReadOnlyMemory) 然后用 SimdLinq 查询
zealotpuppy
248 天前
一万条数据,qps 不到 1 万,这你随便用什么东西都能搞定的事情,你确定瓶颈是在查询数据本身吗?
jstony
248 天前
才几万条数据还折腾啥,直接一股脑读到内存里,爱咋查咋查。
imokkkk
248 天前
全查出来内存里再搞事情吧 内存里操作和 IO 效率不是一个量级的
SmiteChow
248 天前
这么点数据啊,全返回给前端,爱怎么用怎么用。
duluosheng
248 天前
就这点数据,缓存+优化索引就行。
Y25tIGxpdmlk
248 天前
纠结遍历干啥,这么点东西,直接内存不就完了,遍历有咋滴,你心疼内存还是心疼电费啊?
JKeita
248 天前
几万条一次性全查出来筛选就行了。
freewind
248 天前
用 Dict<int, List<T>>保存, 先用 width 取 List,再用 Linq where 查一下
cat1879
248 天前
几万条应该没有什么压力吧,直接数据库查呀,你一边减库存还得一边加库存吧。做好锁表动作就好,问题不大
bthulu
248 天前
@cat1879 查一遍是没压力, 这是要瞬间根据不同条件查几千遍.
815979670
248 天前
@wanguorui123 甚至用 SQLite 的内存模式 不落盘 也可以
wxf666
248 天前
@bthulu 楼上这么多人给出的方案,你给点反馈呀?

1. 全读出来,存数组里,直接遍历找
2. 全读出来,存哈希表里,精确查找
3. 全读出来,排序后存数组里,可范围查找
4. 全读出来,丢到 Redis 里,再查
5. 全读出来,每个丢到一个文件里,根据文件名查
6. 用 MySQL 内存表
7. 用 SQLite 内存表
8. 用 MySQL 存储过程写逻辑


个人认为,从速度上说,内存里用哈希表/ B 树/排序后数组二分查找,

> SQLite 内存表(这个每秒只能几万次)> MySQL 存储过程(页面缓存还是有些慢)>数组遍历( 99%无用功)

>丢到 Redis 查(几千次网络开销)> MySQL 内存表(几千次网络开销)>存几万个文件再查(几千次文件系统开销)
bthulu
247 天前
@wxf666 我目前采用的方案: 直接拉到内存里, 按 id 生成字典. 然后对 2 个区分度相对高的必查字段排序后生成了 1 个 List<Index>.

```
public struct Index(int Width, GsmId[] GsmIds);
public struct GsmId(int Gsm, int Id);
```

每次查询时, 先二分法查找 Width, 再对结果集遍历, 在 GsmIds 中二分法查找 Gsm, 得出满足 Width 和 Gsm 的 id 结果集, 再从字典中取回数据本体生成新的结果集.

这时候的结果集就已经只有几十条了, 其余字段查找, 直接在这个结果集中遍历
bthulu
247 天前
针对 Width 的二分查找, 在找到符合范围的数据后, 继续往上 100 条一跳查找是否满足条件, 不满足则往上 10 条一跳查找, 还不满足就往上一条条查找, 找到起始点. 同样往下找到结束点.
针对 Gsm 的二分查找, 因为每个 Width 对应的 Gsm 不会有太多, 二分查找到符合条件的数据后, 就不做 100 条一跳了, 直接 10 条一跳转 1 条一跳.
22092
246 天前
怪,用到 NET8 又要效率为甚么还用 List<T>,而不用 ReadOnlyMemory<T>,Span<T>等内存优化合集
生成字典似乎已经遍历一次,又要生成 List<T>占内存,LINQ 性能有应该不会这么差吧.(为甚么不用呢)
主要是生成的字典用一個查询就失效了,字典的重用时优勢
而且直接遍历一次,又有必查字段,可以做个迭代器 EX 在途中找到符合条件的数据再 yield 出去处理..
最后都拉到内存了,用 ConcurrentDictionary , SimdLinq 以及 Parallel 作个多线程查询更好
如果这些属性可组织起來,可以看下抽象语法树,表达式树有没有帮助

i7-12700 16GB 256G
一万多库存, 定时任务, 30 秒左右执行一次, 执行时间尽量控制在几百毫秒内, 完成几千次查询(每次查询需要针对库存的多个属性进行多次查询)
从这些情况看,不是大家的方案不好,而是你认为机器太差不合适
有独立机器,不是必要在 VM 内的 Docker 跑程序已经很好了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1032362

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX