客户库存有一万多, 要将这一万多库存按客户要求分散到几百个工位上, 需要针对库存的多个属性进行多次查询, 循环里套循环, 能查上千次甚至更多.
这种情况下, 我是直接数据库查, 还是将数据一次全拉到内存, 在内存里查更好?
数据库查可以走索引, 内存里可就没索引查一次就是全量遍历一次了. 如果有内存里支持索引的列表就好了. 语言是.net8.
别说什么优化查询方案一次查询搞定的了, 这不可能. 现实业务就是各个工位之间关系也是错综复杂, 只能这样查了.

感觉大家伙好像没 get 到这个问题难点在哪里.数据量是不大, 查一次不管怎么查都问题不大.但是, 这里是要在几百毫秒内完成几千次查询, 每次查询用到的字段值都不相同, 用到的字段名, 字段数量也会有变化.程序跑在一台戴尔(Dell)成就 3710 上, 数据库也在这上面.不要问为什么不用专用服务器, 这是制造业, 项目几个亿, 但是服务器确实就是普通家用机器. 我天天蹲在集装箱里开发你们敢信?

全读出来,存到 HashMap 里,不也相当于有索引了吗?

就这么点儿数据,内存里面就算没索引也是比数据库快很多。

这个你咋存? 比如某个属性 width, 范围从 800, 850, 900, 一直到 3000. width=800 的几十条, width=850 的有几条, width=900 的又有几十条, 咋个存到 hashmap 里去?难道按 id 作为 key 存进去? 问题是我这查询条件没有一个地方用到 id, 都是根据属性查的.

财大气粗就用内存呗

问题是不走索引每次都是遍历啊. 比如 1 万条查 1 千次, 平均每次查出来 10 条数据, 对于有索引来说, 每次查询只需要定位最大值和最小值, 然后将中间的依次取出即可. 那 10 条数据走一次索引, 接触到的数据可能还不到 20 条. 一千次就是 2 万条.如果走内存遍历, 查一次就是接触 1 万条数据. 一千次就是一千万条也就是数据库多了一千次 IO, 但少遍历了 998 万条数据.

存成二维数组就行,不过几万条你直接遍历也没事,内存遍历也比走网络查数据库快多了

数据就在你手头上,直接定义 c#数组加.where 跑跑试试呗。

直接查库,也不用判断索不索引的。那么丁点数据,有啥问题?

几万条,直接内存呗。这才多大点

几万条内存不随便放么。

#3 键是宽度值,值是(库存 ID/引用/指针/…)数组?或者,你也模仿数据库的底层存储结构,内存里也用 B 树存储呗。。

一万条数据?不会增加和减少?那就全部内存,直接正则匹配即可,快到让你怀疑人生。

描述里面的 很短时间也没说清楚, 1 、 能不能平均到 每秒多少次 sql 查询2 、是几百个终端近乎同时发起查询?有这么高频的查询3 、mysql 支持读写分离,有没有额外机器给你弄同步数据库用于查询讲原始需求会好很多,方案都可能变掉,比如用 redis 先查一部分,然后再去 mysql 里面查更详细信息。(瞎举例)

不需要每秒查询, 无并发. 就一个定时任务, 每 30 秒左右执行一次, 执行时间尽量控制在几百毫秒内. mysql 就普通电脑, 这是工业用的, 不存在读写分离什么的, 就一普通家用 dell PC 机上运行.

Mysql 内存缓冲区写大点比如实际上库 10G 、PoolSize 64G ,数据库整个就自动放进内存里了

这个量你怎么做都行

你猜为啥 Redis 要放内存里面只要内存没爆,就全放内存肯定不会错

拉到本地存 SQLite 在查询 SQLite 里的数据库快很多,SQLite 充当一级缓存

用数据库查啊,这么点量会很慢吗?用数据库查实现起来多简单啊。建议先按数据库写,实测不行了再想优化方案。

把数据库放到内存中……

设计数据库的又不是傻子,你这种热数据肯定读到内存缓冲池后后面都是从内存读了,有时候真的建议多看看数据库设计原理

数据库处理这几千个请求就得创建几千次线程,这不耗费资源吗?

还是那句话,设计数据库的又不是傻子,数据库内部有线程池实现,提问前多动动脑子

那就复制一份数据到 redis 再查dotnet 8 的话,还有另一个选择:微软最新推出的 Garnet ,也是用 dotnet 8 写的,是 Redis 的替代品

才几千次,还能走索引,怕个球。来点护城河,还可以把一小部分逻辑变成存储过程,就更不用担心了

一万多条其实很少了.. 你可以先用数据库查,看看性能表现

最简单的直接根据你要的属性去分组就行了,不会占多少内存的,速度嗖嗖的。

动手实现一遍, 之后压测试试呗

其实这些数据并不多的,直接内存查吧,走 MySQL 的磁盘 IO 很慢的

有一种很愚蠢但是可能非常高效的做法,就是把上万条数据全部在一个目录下一一对应生成本地文件,查询的时候直接判断对应路径是否存在,这个理论上的时间复杂度是 o(1),如果你查的数据不敏感并且更新数据比较少+懒惰的话你可以试试这个

精确查找还是需要范围查找?如果是精确查找,可以用 HashMap 数据结构存,key 是 width ,value 是一个列表,那通过查询 key=800 就能直接查出那几十条 width=800 的数据;如果需要范围查找,可以定义一个按需要查询的条件排好序的列表,然后写一个简单的二分法进行查找最小值,然后再进行遍历,直到最大值的时候停止,这样比遍历全部数据效率要高得多;如果是有多个需要查询的条件,那就需要为每一个查询条件创建一个 HashMap 或者有序 List ,其实就跟数据库的原理一样,通过多个条件查询查出来后,将结果做一次交集,就是最终需要的结果了。当然,这样肯定会增加开发成本,就看你怎么权衡了。

其实就是仿数据库的索引一样,在内存手动给每个字段做一个索引

mysql 表使用内存表,ENGINE=MEMORY ,这么点数据都放内存。只需要改表类型,其他都不需要动

10000 的数据量, 直接放内存 list, for each data line, 用你的所有条件 filter 就行.一次 filter 不行要么就属性打平做大宽表, 那么多做 filter,存内存肯定比 io 快

机器配置,系统架构,业务逻辑,啥也不说,鬼看了都难搞。万一楼主的服务器是 J1900 上的 PVE 里的虚拟机里的 docker 呢?万一楼主的服务器接在一台百兆交换机上呢?

一万多条数据,你直接内存数据库查就行了,剩下的都不用你管(量太小了)

30 秒一次,单机数据库,无并发,总共就一万多条数据…… 这么点压力应该远远没到需要优化性能瓶颈的地步吧

你要做的工作远不止这个问题,而这个问题实际写代码测试一下,你收获的结果会更多

dotet 不是有 Linq 吗?而且这种情况通常最好的建议是,通过业务逻辑,用几个字段对表数据进行分组。例如:有个数学成绩属性,全班有 30%数学成绩在 80+,40%是 60+,30%是 30+,全班 60 人,你不应该无脑查询 60 次,也不应该一次全查出,你应该是先查出 80 分以上的,然后再内存中对这些数据进一步筛选。这样一共查下三次,内存容量操作也适中。反正大概这个意思,做业务开发不要脱离业务逻辑。

我觉得这应该是个算法问题,而不是查询问题。

Mysql 做好索引, 开启查询缓存, 使用 chunk 或者 游标 cursor 查询, 每次多查点 , 使用连接池 , 需要并发的话可以使用协程

redis

  1. 目前如果优化数据库索引设计是否可以达到你的要求?2. 如果各种优化了还是达不到性能要求,上 Redis 大概率是一个不会错的选项不一定是最优解,但是大概率不会错。3. 底层是 MySQL 的话,别太期望 Query cache(这玩意默认应该是禁用的)我的思路跟理念:能少一个模块就少一个模块,维护成本压到最低。以 Redis 为例,Redis 数据的更新策略? Redis DB 自己的维护成本如何?是否熟悉 Redis 数据迁移?所以,不要一开始就 over design ,建议先尽量优化数据库设计(也是对技术深入研究的一个自我要求)

    兄弟,查询缓存默认被关闭应该是有原因的,可以研究看看是否真的适合自己的业务场景再开启

参考 Hive 和 Impala ,第一次查询时比较慢的,尤其是刷完元数据以后,但查询一次以后,就比较快了。 你就参考这两个设计就行。

如果数据库和应用服务器是同一台服务器 , 就用数据库。 原因因为你的数据结构不是单纯的 k-v ,利用数据库的索引更好的实现查询。 放在内存里的开销也没有想象中那么低 ,几万条数据,可能要经过几次查询遍历,相当于循环几万次。如果不是同一台服务器,还是建议内存吧,不然就算数据库很快,最基本的网络 IO 开销都挺大了 ,可能最简单的查询都需要 10~20ms

数据存数据库,数据量很小,又是定时任务,实时性不高,没必要放内存,不会慢,稍微慢点问题也不大。业务复杂要考虑的是业务代码的可读性,可维护性和可扩展性。可以考虑按照业务模型做缓存,防止重复查询的频繁查库即可

上万条数据真没多少,担心 DB 没有索引或有远程网络调用开销,读到内存里来,每次遍历这个 O(n) 的 n 也不过 10K+,相比内存访问带宽和 CPU 处理能力,完全不用看假定上万条是 10 万条数据好了,这就是 100K ,每条数据占 1KB 内存,那也就是 100MB ,普通的 PC 机还能挪不出这 100MB 的内存来?具体还是要看业务场景,是同机器上的数据库还是不同机器提供的数据库,数据检索是单条件还是多条件,带不带索引,建索引和维护索引的成本,查询条件更大概率是方便 SQL 化的还是方便代码实现的

如果只是 1 万多条数据,数据库查询完全就能解决,你需要的是如何拆解业务逻辑做到最优化的方案,例如业务查询分组等等,使数据库查询代价最小。

提一个可能大家都没注意的点:page cache + 数据库 cache 。实际上短期大量查询大概率都是在 cache 中的。如果觉得内存中操作太麻烦了话,还是考虑走 db 把。

这个数据量并不多...几百万的数据 sqlite 在树莓派上,做这种关联查询单次也能压到几百 ms 内...不过看描述感觉是先用一次查询获得下次查询的条件,进行嵌套查询,其实很多时候自己写各种数据结构算法还真不一定有数据库或者语言自带的数组便利好用,建议在实际运行的环境下试试再说

普通单机 MySQL 每秒可以查询 1 万多次。

怎么楼上这么多菜鸡。先说结论: 如果要查询一千多次,肯定是先全查出来放到内存里啊。你知道 1 千多万次遍历要执行多久吗?不会超过几毫秒!每次去 mysql 查,网络耗时有多久???所以这还用比较吗

内存表?

mysql 不是有内存表,再找找其他的呗,同步就是了

我现在在做的一个项目就跟你比较像,不过数据量比你还要大上十几倍。这种数据量看着对于现代数据库来说不算什么,但是能保证后面实际业务过程中数据量不会增加吗?确定不会有多个用户同时操作?确定其他模块不需要如此大量读写数据?确定其他模块不会调用这种大数据量的方法?能确定实际部署的时候,客户的服务器不是石头盘或者数据库玩拆分服务器 cpu 跟得上?直接放数据库在硬盘读写的话大概率后面用户体验很差,或者只能把这种方法写成异步处理,但是业务流程得小改。

#8 查询次数太多了,会有额外的 IO 耗时消耗

我自己没试过,可以考虑这种,读取一次 mysql 数据到本地内存数据库,内存数据库也可以建索引,之后查内存数据库比如:sqlite 内存模式 memory 索引

而且不知道你们交付的时候有没有压测流程,到时候运维找上门问为什么硬盘 IO 资源打满了就有趣了

另外这个 cqengine 看着也不错,可以快速查询的集合 github.com/npgall/cqengine

你提到是 mysql 做定时任务, 可以直接 Stored Procedure + Scheduled Jobs 做, 准时高效(mysql,sqllite 可以啟用内存模式)想自由更改而用 NET8 的 可以将数据一次全拉到内存(用 ReadOnlyMemory) 然后用 SimdLinq 查询

一万条数据,qps 不到 1 万,这你随便用什么东西都能搞定的事情,你确定瓶颈是在查询数据本身吗?

才几万条数据还折腾啥,直接一股脑读到内存里,爱咋查咋查。

全查出来内存里再搞事情吧 内存里操作和 IO 效率不是一个量级的

这么点数据啊,全返回给前端,爱怎么用怎么用。

就这点数据,缓存+优化索引就行。

纠结遍历干啥,这么点东西,直接内存不就完了,遍历有咋滴,你心疼内存还是心疼电费啊?

几万条一次性全查出来筛选就行了。

用 Dict<int, List>保存, 先用 width 取 List,再用 Linq where 查一下

几万条应该没有什么压力吧,直接数据库查呀,你一边减库存还得一边加库存吧。做好锁表动作就好,问题不大

查一遍是没压力, 这是要瞬间根据不同条件查几千遍.

甚至用 SQLite 的内存模式 不落盘 也可以