@tasy5kg,反正我印象中 win 7 一直挺稳定的。毕竟人家测试的质量也比 win10 11 好
无论如何,win 7 也逐步成过去时了。连 Python 不支持 win 7 也快 2 年了。。
感觉我下一台笔电,至少 32 GB。省得整天陷入内存焦虑(就像 K40 有 12 GB 内存一样)
碰到微力同步这种莫名其妙吃固态的应用,也能开个 20 GB 内存盘,任它干个 100 TB 都不怕
这位用户还没有留下个人签名。
@tasy5kg,反正我印象中 win 7 一直挺稳定的。毕竟人家测试的质量也比 win10 11 好
无论如何,win 7 也逐步成过去时了。连 Python 不支持 win 7 也快 2 年了。。
感觉我下一台笔电,至少 32 GB。省得整天陷入内存焦虑(就像 K40 有 12 GB 内存一样)
碰到微力同步这种莫名其妙吃固态的应用,也能开个 20 GB 内存盘,任它干个 100 TB 都不怕
@tasy5kg,我记得以前 win 7 没有此问题的
目前我觉得 win 7 是最稳定的一个系统
@tasy5kg,我也有同样的问题!!!
我是 Win 10,一般用了几天不重启,内存泄漏就很严重了
关掉所有程序,都会占用 4~5 GB。。
我实际使用感知也不太大,但固态扛下了一切
特别这一星期,被微力同步折腾的死去活来,感觉系统固态盘写了快 1TB 了,但实际数据没下多少 GB。。
@tasy5kg,感觉现在浏览器应用越来越多,IDE 吃内存又狠。
你觉得日常够用吗?一般占用多少内存?11、12 GB ?
@tasy5kg,你的电脑内存多大啊?16GB吗?
@李沐沐,5 楼的尝试了吗?效果咋样?
SELECT family_uid, id, name, relationship, Gender, nation, uid, phone, Culture, marriage
FROM personnels_too
ORDER BY family_uid, family_uid != uid, id;
@李沐沐,不能写成这样吗?
SQLite 代码看需要加索引
WITH
data(id, name, relationship, Gender, nation, uid, phone, Culture, marriage, family, family_uid, life, Village, remarks, WorkingAddress, addtime, uptime) AS (
VALUES
(1, '张三', '户主', '男', '汉', '101100202202052252', '18888888888', '高中', '已婚', '张三', '101100202202052252', 1, '田系组', NULL, NULL, '', ''),
(2, '李娥', '配偶', '女', '汉', '101100202102052243', '18888888888', '高中', '已婚', '张三', '101100202202052252', 1, '田系组', NULL, NULL, '', ''),
(3, '王五', '户主', '男', '汉', '101100201102052243', '18888888888', '高中', '已婚', '王五', '101100201102052243', 1, '田系组', NULL, NULL, '', ''),
(4, '丽丽', '女儿', '女', '汉', '101100201702052243', '18888888888', '高中', '已婚', '王五', '101100201102052243', 1, '田系组', NULL, NULL, '', ''),
(5, '李爱', '女儿', '女', '汉', '101100202204052243', '18888888888', '高中', '未婚', '张三', '101100202202052252', 1, '田系组', NULL, NULL, '', '')
)
SELECT family_uid, id, name, relationship, Gender, nation, uid, phone, Culture, marriage
FROM data
ORDER BY family_uid, family_uid != uid, id;
-- ORDER BY family_uid, relationship != '户主', id;
| family_uid | id | name | relationship | Gender | nation | uid | phone | Culture | marriage |
|---|---|---|---|---|---|---|---|---|---|
| 101100201102052243 | 3 | 王五 | 户主 | 男 | 汉 | 101100201102052243 | 18888888888 | 高中 | 已婚 |
| 101100201102052243 | 4 | 丽丽 | 女儿 | 女 | 汉 | 101100201702052243 | 18888888888 | 高中 | 已婚 |
| 101100202202052252 | 1 | 张三 | 户主 | 男 | 汉 | 101100202202052252 | 18888888888 | 高中 | 已婚 |
| 101100202202052252 | 2 | 李娥 | 配偶 | 女 | 汉 | 101100202102052243 | 18888888888 | 高中 | 已婚 |
| 101100202202052252 | 5 | 李爱 | 女儿 | 女 | 汉 | 101100202204052243 | 18888888888 | 高中 | 未婚 |
看不懂这是个啥需求啊。。
@淡然,
从表a获取status状态为0的token,获取到后标记status为1
不加锁,多个连接同时获取同一个 status == 0 的标记记录,不是很正常吗?
然后多次 update xxx set status = 1 where id = ? 呗
@庸人,那就不知道了。。我用 3 楼的法子,都能绕开一段时间的 cloudflare。。
你本地运行着啥?有源码的话,直接瞅瞅逻辑呗?
@庸人,浏览器打开【开发工具】,在【网络】里,把这个请求复制成【curl】请求,然后粘贴运行试试?
@罐子,它们是如何流出的呢?为嘛源码没有顺便流出来呢?
@老虎会游泳,我做了下『闭包表』和『改良后的邻接表』的测试 (结尾附上一键建表和查询的 SQL 供测试)
MySQL 8.0.29 和 SQLite 3.39.0(<pid, id>, is_leaf) 型邻接表』结果如下 (多次测试稳定后):
| 表结构 | MySQL |
SQLite |
|---|---|---|
| 闭包表 | 1.3 秒 | 0.13 秒 |
| 递归邻接表 | 1.2 秒 | 0.60 秒 |
| 理想中递归损耗很小的邻接表 | 0.6 秒 | 0.12 秒 |
| 表结构 | MySQL |
SQLite |
|---|---|---|
| 闭包表 | 1.2 秒 | 0.12 秒 |
| 递归邻接表 | 0.5 秒 | 0.13 秒 |
| 理想中递归损耗很小的邻接表 | 0.4 秒 | 0.10 秒 |
4W 多次的 ref 级 WHERE pid = ?,还是能和 66W 次 eq_ref 级的 WHERE id = ? 过过招,甚至更快的。而且,磁盘IO越慢,这个差异应该越大。
数据库们的 WITH RECURSIVE 查询,损耗有点大。
MySQL 好歹每次递归都将上一次所有结果当作一张表来计算。但大概 5 次递归的耗时,就比非递归的多一倍了
SQLite 最摆烂,每次递归只取以前结果的一行来计算,直到取完为止。所以有 66W 次的递归,耗时大概 5 倍多。。
Extract a single row from the queue.
Pretend that the single row just extracted is the only row in the recursive table and run the recursive-select, adding all results to the queue.
SQL下面 SQL 基本可用于 MySQL 和 SQLite (不支持的特性,数据库会报错,改掉即可)
PRAGMA cache_size = -204800; -- 允许 SQLite 缓存 200 MB
-- 闭包表查询
SELECT COUNT(*), SUM(code), SUM(CHAR_LENGTH(name)) -- SQLite 写法:SUM(LENGTH(name))
FROM closure_tree
FORCE INDEX (idx_closure_tree) -- 我这测试,MySQL 不加这行,耗时翻好几倍。SQLite 需去掉此行
JOIN closure ON id = descendant
WHERE ancestor = 0;
-- 递归邻接表查询
WITH RECURSIVE
find(id, code, name, is_leaf) AS (
SELECT id, code, name, is_leaf
FROM adjacent
WHERE pid = 0
UNION ALL
SELECT b.id, b.code, b.name, b.is_leaf
FROM find a
JOIN adjacent b ON NOT a.is_leaf AND b.pid = a.id
)
SELECT COUNT(*), SUM(code), SUM(CHAR_LENGTH(name)) -- SQLite 写法:SUM(LENGTH(name))
FROM find;
-- 理想中,没有递归损耗的邻接表查询
SELECT COUNT(*), SUM(b.code), SUM(CHAR_LENGTH(b.name)) -- SQLite 写法:SUM(LENGTH(b.name))
FROM adjacent a
LEFT JOIN adjacent b ON b.pid = a.id -- SQLite 需要 LEFT JOIN,否则耗时翻几倍
WHERE NOT a.is_leaf;
SQLPRAGMA cache_size = -204800; -- 允许 SQLite 缓存 200 MB
-- 闭包表查询
SELECT COUNT(*), SUM(code), SUM(CHAR_LENGTH(name)) -- SQLite 写法:SUM(LENGTH(name))
FROM closure_tree
FORCE INDEX (idx_closure_tree) -- 我这测试,MySQL 不加这行,耗时翻好几倍。SQLite 需去掉此行
JOIN closure ON id = descendant
WHERE ancestor = 0
AND distance = 5;
-- 递归邻接表查询
WITH RECURSIVE
var(depth) AS (
SELECT 5
),
-- 递归部分查前 N - 1 层
find(id, is_leaf, depth) AS (
SELECT 0, FALSE, var.depth - 1
FROM var
UNION ALL
SELECT b.id, b.is_leaf, a.depth - 1
FROM find a
JOIN adjacent b ON b.pid = a.id
WHERE a.depth > 0
AND NOT a.is_leaf
)
-- 最后一次性 JOIN 第 N 层
SELECT COUNT(*), SUM(b.code), SUM(CHAR_LENGTH(b.name)) -- SQLite 写法:SUM(LENGTH(b.name))
FROM find a
CROSS JOIN adjacent b ON a.id = b.pid -- SQLite 要加 CROSS,否则耗时翻几倍
WHERE a.depth = 0;
-- 理想中,没有递归损耗的邻接表查询(需要根据层数 N,动态生成 SQL)
SELECT COUNT(*), SUM(t5.code), SUM(CHAR_LENGTH(t5.name)) -- SQLite 写法:SUM(LENGTH(t5.name))
FROM adjacent t1
JOIN adjacent t2 ON t2.pid = t1.id
JOIN adjacent t3 ON t3.pid = t2.id
JOIN adjacent t4 ON t4.pid = t3.id
JOIN adjacent t5 ON t5.pid = t4.id
WHERE t1.pid = 0;
MySQL 一键建表 SQL(在我低配笔记本和固态上,大约执行了 1 分钟)
-- 允许 200 MB 的内存表
SET max_heap_table_size = 200 << 20;
-- 建临时数据表,装载 csv 数据,以及计算序号和父子关系
CREATE TABLE data (
code BIGINT NOT NULL,
p_code BIGINT NOT NULL,
type TINYINT NOT NULL,
name VARCHAR(25) NOT NULL,
id INT NOT NULL,
pid INT NOT NULL,
PRIMARY KEY (code) USING BTREE,
INDEX USING BTREE (id),
INDEX USING BTREE (pid, id)
) ENGINE = MEMORY;
-- 加载 csv
LOAD DATA INFILE 'area_code_2022.csv'
INTO TABLE data
CHARACTER SET UTF8MB4
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
(code, name, type, p_code);
-- 按照 code 顺序计算 id
UPDATE data
JOIN (SELECT code, ROW_NUMBER() OVER win row_num
FROM data
WINDOW win AS (ORDER BY code)) t USING(code)
SET id = row_num;
-- 计算 parent_id(不存在的标0)
UPDATE data a
LEFT JOIN data b ON b.code = a.p_code
SET a.pid = IFNULL(b.id, 0);
-- 建邻接表,并从临时数据表填充数据
CREATE TABLE adjacent (
id INT NOT NULL,
pid INT NOT NULL,
is_leaf BOOL NOT NULL,
type TINYINT NOT NULL,
code BIGINT NOT NULL,
name VARCHAR(25) NOT NULL,
PRIMARY KEY (pid, id)
)
SELECT -1 pid, 0 id, FALSE is_leaf, 0 type, 0 code, '' name
UNION ALL
SELECT pid, id, type = 5 is_leaf, type, code, name
FROM data;
-- 建闭包表主表,并从临时数据表填充数据
CREATE TABLE closure (
id INT NOT NULL,
type TINYINT NOT NULL,
code BIGINT NOT NULL,
name VARCHAR(25) NOT NULL,
PRIMARY KEY (id)
)
SELECT 0 id, 0 type, 0 code, '' name
UNION ALL
SELECT id, type, code, name
FROM data;
-- 建闭包表树形关系表
CREATE TABLE closure_tree (
ancestor INT NOT NULL,
descendant INT NOT NULL,
distance TINYINT NOT NULL,
PRIMARY KEY (descendant, distance)
);
-- 递归构建树形关系
INSERT INTO closure_tree(ancestor, descendant, distance)
WITH RECURSIVE
parent_of(orig_id, id, dist) AS (
SELECT id, id, 0
FROM data
UNION ALL
SELECT orig_id, pid, dist + 1
FROM parent_of
JOIN data USING(id)
WHERE id
)
SELECT id, orig_id, dist
FROM parent_of;
-- 为闭包表树形关系表建二级索引
CREATE INDEX idx_closure_tree ON closure_tree (ancestor, distance);
-- 丢弃临时数据表
DROP TABLE data;
SQLite 一键建表 SQL下列 SQL 需要依赖 SQLite Shell 的 .import --csv,核心 SQLite 库不提供此功能。
因此,需要使用命令行的 SQLite 来运行(Windows 可去官网下载个 1~2 MB 的 sqlite3.exe)。
下面使用 Bash Shell 来包装执行命令与 SQL,大约需要运行 30 秒,然后在同目录下生成 150 MB 左右的 test.db。
#!/bin/bash
sqlite3 :memory: <<'EOF'
-- 在内存中计算,最后整理紧凑才写入文件
PRAGMA TEMP_STORE = MEMORY;
-- 导入 csv 文件至临时表
CREATE TEMP TABLE csv (code INTEGER PRIMARY KEY, name TEXT, type INT, p_code INT);
.import --csv area_code_2022.csv csv
-- 建邻接表
CREATE TABLE adjacent (
id INT NOT NULL,
pid INT NOT NULL,
is_leaf INT NOT NULL,
type INT NOT NULL,
code INT NOT NULL,
name TEXT NOT NULL,
PRIMARY KEY (pid, id)
) WITHOUT ROWID;
-- 填充邻接表
INSERT INTO adjacent (pid, id, is_leaf, type, code, name)
SELECT -1, 0, FALSE, 0, 0, ""
UNION ALL
SELECT p_code, ROW_NUMBER() OVER (), type = 5, type, code, name
FROM csv
ORDER BY code;
-- 建临时索引,提速 code 搜索
CREATE INDEX i ON adjacent (code);
-- 更新 pid
UPDATE adjacent
SET pid = t2.id
FROM adjacent t2
WHERE adjacent.pid = t2.code;
-- 丢弃临时索引
DROP INDEX i;
-- 建 id -> pid 索引
CREATE INDEX idx_adjacent_id ON adjacent (id);
-- 建闭包表主表
CREATE TABLE closure (
id INTEGER PRIMARY KEY,
type INT NOT NULL,
code INT NOT NULL,
name TEXT NOT NULL
);
-- 建闭包表树形关系表
CREATE TABLE closure_tree (
ancestor INT NOT NULL,
descendant INT NOT NULL,
distance INT NOT NULL,
PRIMARY KEY (descendant, distance)
) WITHOUT ROWID;
-- 填充闭包表主表
INSERT INTO closure (id, type, code, name)
SELECT id, type, code, name
FROM adjacent;
-- 递归构建树形关系
WITH RECURSIVE
parent_of(orig_id, id, dist) AS (
SELECT id, id, 0
FROM adjacent
UNION ALL
SELECT orig_id, pid, dist + 1
FROM parent_of
JOIN adjacent USING(id)
WHERE id
)
INSERT INTO closure_tree (ancestor, descendant, distance)
SELECT id, orig_id, dist
FROM parent_of;
-- 为闭包表树形关系表建二级索引
CREATE INDEX idx_closure_tree ON closure_tree (ancestor, distance);
-- 整理紧实数据库后,写入磁盘
ANALYZE;
VACUUM INTO 'test.db';
EOF
@罐子,这些游戏的服务端,全都是只有可执行文件,没有源码,是吗?
@淡然,回调 PromptSetValue(v => item.it = v) 或 异步 PromptSetValue().then(v => item.it = v) ?
@淡然,function PromptSetValue(e, key) ?
@淡然,下面的写法有何不妥吗?你原始问题是啥?
@淡然,因为 js 没法引用对象的键?
@老虎会游泳,老虎这么多年,没有啥树形数据要存吗?之前都用的啥方案?
@庸人,
主要是我其实更习惯用管道这样的方式
不能在匿名管道内修改外部的变量!(如:jq | readarray、sum=0; seq 3 | while read -r i; do (( sum += i )); done)
因为这会开启一个子 shell,然后在子 shell 中,readarray 将 jq 的输出转成数组。
等这一行执行完毕,子 shell 就会退出,刚整理好的数组也随着进程结束而消失了。
所以,只能用 <<< 或 < <(...) 的形式。
前者需要完全准备好一个字符串,再作为 stdin 喂给所在的命令。我觉得没必要,没这么干
(试想,你拷贝一个 1GB 的文件,会申请 1GB 的内存,全部读取完成后,再写入至新文件吗?)
后者,<(...) 是将 ... 的 stdout 重定向至某个文件(一般是具名管道),然后将此文件作为 stdin 喂给所在命令
(如果是管道实现,则一般是 4KB 缓冲区)
但是当我单拧出来一个数组,那么结尾就会有一个换行🤣🤣
使用 readarray 时指定 -t 参数,会自动删除行末的换行符
@老虎会游泳,那个博主给出新的解决方案了,速度上确实应该会很快,但空间占用也很恐怖。。
那个博主新的表结构为:
CREATE TABLE 闭包表 (
祖先 INT,
后代 INT,
距离 INT,
PRIMARY KEY (后代, 距离),
KEY (祖先, 距离)
);
使得有如下两种索引:
(后代, 距离, 祖先)(祖先, 距离, 后代)就能高效应对下列查询了:
(✔查询节点, ✔1 或 2 或 任意, ❓<要获取的后代节点>)(✔查询节点, ✔1 或 2 或 任意, ❓<要获取的祖先节点>)下列查询会小范围扫表,但问题不大:
某后代节点与某祖先节点的距离:走聚集索引 (✔查询后代节点, ❓<要获取的距离>, ❌查询祖先节点)
只要 查询后代节点 层级没有深到离谱,扫表范围也就连续的几行几十行而已。
一个 66W 的 5 级地区表,就要配套一个相当于 780W 的闭包表,快接近 12 倍于主表的辅助表了。。
如此恐怖的空间换时间方案,到底能快多少呢?真的值得投入这么多空间来提速吗?
@庸人,你的需求是要备份当下的网易云歌单吗?还是啥。。
@庸人,你说下原始需求,感觉会有更好的实现方式
@庸人,比如:
$ readarray -td $'\0' arr < <(jq -rj '[.[].name] | join("\u0000")' <<<'[{"id": 1, "name": "a\nb\n"}, {"id": 2, "name": "c\nd"}]')
$ declare -p arr
declare -a arr=([0]=$'a\nb\n' [1]=$'c\nd')
如果你不担心你的 name 里有换行符的话,可以直接:
$ readarray -t arr < <(jq -r '.[].name' <<<'[{"id": 1, "name": "ab"}, {"id": 2, "name": "cd"}]')
$ declare -p arr
declare -a arr=([0]='ab' [1]='cd')
@庸人,直接回答:可以用 Bash 的 readarray 来一次性读到某个数组
另外:
Bash Shell 更适合交互式和简单脚本使用。含有数组、字典甚至更复杂数据结构的,可能都值得你考虑换其他语言了jq 来一次性生成你最终要的数据?