使用的 CH 版本:19.16.9.37

官方的文档看得晕头转向,可能还是自己英文功底不够,在读完官方的相关文档后,自己又做了大量测试,总结一下心得。

推荐阅读的官方文档:

如果看完本文仍有疑惑的地方,建议阅读下官方文档。

在 CH 中单独提及“副本”涉及到两个概念,副本表和副本分片,顾名思义,一个是为表做副本,一个是为分片做副本。

为了避免混乱后面会分开说这两种副本。

副本表(replicated table)

副本表比较容易理解,所有的副本表之间会相互同步数据,注意是相互同步。

副本表从使用角度来看并没有主副之分,任何一个副本表都可以拿来正常使用,
因此在创建副本表时,即便是第一个副本表也需要用 Replicated* 系列引擎创建。

阅读全文 »

先扯一堆:byte(字节),bytes(字节流),二进制,十六进制,编码
今天跟同事讨论起了上面一堆名词之间的定义和关系到底是什么,不啦不啦个把小时之后得出了以下结论。

byte 与 二进制

byte 是二进制的长度单位(位数,为了便于理解后面使用长度一词),一个 byte 表示长度为 8 的二进制,即通常所说的:一个 byte 是 八个 bit(位)

既然 byte 是二进制的长度单位,那么编程语言里的其他类型呢?

它们其实也是二进制的长度单位,但是表示的长度不同,比如 int 表示 4 个字节(通常)也就是说 int 其实表示长度为 4 * 8 = 32 的二进制,其他类型以此类推,注意,char 类型表示一个 byte,也表示长度为 8 的二进制。

byte 是长度单位为什么能表示数值大小?

一个二进制数既然确定了其长度,那么也就确定了其能表示的数值范围,因此一个 byte 也就能表示出长度为 8 的二进制数所能表示的任何数值。

要注意,byte 是先确定了二进制长度,然后才确定了数值大小,具体的数值大小要看这固定长度的二进制每一位都是什么内容。

编码又是什么?

我们将编码分为狭义和广义两种。

阅读全文 »

列表初始化,成员初始化器列表,初始化列表,傻傻搞不清楚

唉,为什么总有刁民乱起名

std::initializer_list

(译:花括号初始化器列表)

简介:
可以将其理解为类/模板类

备注:
这表示一种花括号数据类型 {x, y, ...}
当然,这也是一种普通的数据类型,其他类型怎么用,它就可以怎么用,如:

1
2
3
std::initializer_list<int> foo = {1, 2, 3, 4} // 声明此类型数据并赋值
auto foo = {1, 2, 3, 4} // 同上
void func_bar(std::initializer_list<int> arg_var) {} // 声明此类型数据为形参

中英文链接:
https://zh.cppreference.com/w/cpp/utility/initializer_list
https://en.cppreference.com/w/cpp/utility/initializer_list

List initialization

(译:列表初始化)

阅读全文 »

存储相关

页,数据库管理数据的最小单元
区,预请求磁盘空间单元,确保读取时的效率,根据数据量延伸出四种状态,某些状态下的区直属于表
段,区的集合
表,表空间,管理段和部分区

索引相关

在指定索引时尽量设置索引的 唯一 属性,这种唯一的二级索引,在 等值 查询时性能近乎与主键等价,等值查询不包括 IS NULL 查询

在查询时尽量避免回表(再从聚簇索引拿数据),当查询列和查询条件都是索引时即可避免

使用 OR 时要慎重:一个使用到 索引 A 的搜索条件和没有使用 A 的搜索条件使用 OR 连接起来后将无法使用 A
SELECT * FROM single_table WHERE key2 > 100 OR common_field = ‘abc’;
其中 key2 和 common_field 都有各自的索引
那么上述查询语句将无法按照预期使用 key2 的索引,而是会拿所有 key2 的值去回表,在回表的时候使用 common_field 的索引

对于联合索引,查询条件要注意索引列声明的顺序,且只有左边的查询条件是 等值 查询时右边的查询条件才能继续使用联合索引

索引列必须和常数比较才会使用索引,两个列进行比较则不会使用到索引

在执行连接查询时,驱动表被访问一次,被驱动表可能会被访问多次,次数与驱动表数据量有关(扇出)

在创建索引时,如果可以尽量使用唯一索引

阅读全文 »

有时 docker 容器会由于错误修改了某些配置文件而无法启动,如 entrypoint 脚本或服务程序的配置文件等等,如果容器内没有什么有价值的数据,那么重新创建容器自然是首选,本文讨论的是容器不能被删除,该如何修复这种情况。

容器跑不起来,docker exec 命令就无法运行,这意味着无法进入容器,修正有问题的配置文件;此时可以使用 docker cp 命令,将容器内的出问题的配置文件复制出来到主机上,在主机上修正配置文件后,再使用 docker cp 命令将其复制回容器内,覆盖掉容器内的原文件,此时执行 docker start 命令启动容器就可以了。

标题写出来后发现覆盖面有点大,其实要说的只是字面意义上的一点学习小结:

数据库优化:
水平分库,水平分表,使各个库/表的结构相同,但内容不同
垂直分库,垂直分表,使各个库/表的结构不同,且内容不同
库的结构可以理解为包含了哪些表
表的结构可以理解为包含了哪些字段
在垂直拆分的基础上,可以进一步水平拆分

分布式优化:
水平扩展,增加更多节点以达到整体性能增强
垂直扩展,增强单机配置以达到单点性能增强,进而达到整体性能增强
水平扩展优点更多,使用得当的话,对整个系统的可用性,负载均衡都有益处

部分摘录自官方中文文档,python 版本 3.7.4

注意概念区分:生成器函数,生成器,协程函数,协程,异步生成器函数,异步生成器

主要是学习笔记,没有进行过多整理

  • 使用 async def 语法定义的函数总是为协程函数,即使它们不包含 await 或 async 关键字,另外 await,async for 以及 async with 只能在协程函数体中使用(注:以普通函数调用方式调用协程函数时,将返回协程对象,而不是运行协程)

  • 在一个函数体内使用 yield 表达式会使这个函数变成一个生成器,并且在一个 async def 定义的函数体(注:协程函数)内使用 yield 表达式会让协程函数变成异步的生成器(注:以普通函数调用方式调用生成器函数时,将返回生成器对象,而不是运行生成器;以普通函数调用方式调用异步生成器函数时,将返回异步生成器对象,而不是运行异步生成器)

  • 生成器函数与协程(注:函数)非常相似,它们 yield 多次,它们具有多个入口点,并且它们的执行可以被挂起。唯一的区别是生成器函数不能控制在它在 yield 后交给哪里继续执行,控制权总是转移到生成器的调用者

  • 当使用 yield from 时,它会将所提供的表达式视为一个子迭代器,这个子迭代器产生的所有值都直接被传递给当前生成器方法的调用者

  • 启动一个生成器的方法有两种,注意,这两种调用都有返回值,返回的是生成器 yield 的值:

    • 使用内建的 next() 函数,继续使用 next() 函数将继续运行生成器
    • 使用生成器的 send() 方法,但启动时必须传参 None,继续调用 send() 方法将继续运行生成器,此时可以向生成器传入任意值
  • 启动一个协程的方法:导入 asyncio 包,使用 asyncio.run() 函数执行一个协程,注意,需要传入协程对象作为参数,而不是协程函数

  • 注意,await 语句返回指定协程 return 的值(与生成器的 yeild 有区别)

  • 如果只有一个协程在运行的话,代码执行流程与普通函数一样,因为协程函数中的 await <指定协程> 语句将会挂起(阻塞)当前协程,去执行 await 语句指定的协程,直到指定协程执行结束返回后才恢复当前协程

  • 可以使用 asyncio.gather() 函数并发执行多个协程

如题,解决方法:

  1. 安装 sof-firmware
    1
    sudo pacman -S sof-firmware
  2. 创建两个文件:
    1
    2
    sudo touch /etc/alsa/state-daemon.conf
    sudo touch /var/lib/alsa/asound.state
  3. 重启之后应该就能识别到声卡了
  4. 如果没有声音,执行 alsamixer,将声卡取消静音,具体方法可以看: https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Unmuting_the_channels

前段时间给两台机器装了 Manjaro,公司台式主机和 Redmi G 笔记本,使用的桌面环境是 KDE 发现两台机器都不能正常识别声音设备,笔记本是因为直接识别不到声卡,这个问题下一篇文章说一下解决方法,这里先说台式主机的问题。

使用的扬声器其实就是个 3.5 毫米的耳机,在给这台机器重装之前使用的是 deepin 系统,这个耳机是可以正常工作的(虽然不常用,但印象里是可以工作的),但是在 Manjaro 里 KDE 提示找不到声音设备,经过测试当把耳机插入主机后面的插口时是可以工作的,这也说明系统是可以识别到声卡的,谷歌了一圈发现可以给声卡驱动添加启动参数针对一些设备的兼容。这台机器的声卡是 ALC887,可以通过执行一下命令查看开机日志,并搜索 audio 来找出声卡型号:

1
sudo journalctl -xb

然后执行以下命令可以查看内核为这个声卡加载的驱动:

1
2
3
4
5
6
7
8
# lspci -v
00:1b.0 Audio device: Intel Corporation 8 Series/C220 Series Chipset High Definition Audio Controller (rev 05)
Subsystem: Gigabyte Technology Co., Ltd Device a182
Flags: bus master, fast devsel, latency 0, IRQ 31
Memory at f7d10000 (64-bit, non-prefetchable) [size=16K]
Capabilities: <access denied>
Kernel driver in use: snd_hda_intel
Kernel modules: snd_hda_intel

可以发现使用的驱动是 snd_hda_intel,在内核 alsa 相关文档中可以找到有哪些选项:

https://www.kernel.org/doc/html/v5.7/sound/hd-audio/models.html

按照声卡型号搜索,找到对应的选项:

https://www.kernel.org/doc/html/v5.7/sound/hd-audio/models.html#alc88x-898-1150-1220

之后编辑 /etc/modprobe.d/alsa-base.conf 文件(没有则创建),添加以下内容:

阅读全文 »

mysql 索引

学习了《MySQL 是怎样运行的:从根儿上理解 MySQL》中的索引一节,收获颇丰,总结如下。

innodb 索引(组织结构 b+ 树)

用户记录 -> 用户记录数据页-> 目录项记录 -> 目录项记录数据页 -> 更大范围目录项记录 -> 更大范围目录项记录数据页 -> 更大范围…

  1. 用户记录数据页 中包含针对 用户记录 的目录,称为 页目录,用来使用二分法快速查找 用户记录
  2. 目录项记录数据页 是针对 用户记录数据页 的目录,也包含一个 页目录,但用来使用二分法快速查找 目录项记录
  3. 一个 用户记录数据页 对应多个 用户记录
  4. 一个 用户记录数据页 对应一个 目录项记录
  5. 一个 目录项记录数据页 对应多个 目录项记录
  6. 一个 目录项记录数据页 对应一个 更大范围目录项记录

聚簇索引

以上述结构组织数据,且存储了所有 完整 用户记录的索引,一般是主键索引

二级索引

以上述结构组织数据,但数据不存储完整用户记录,仅存储索引列 + 主键列的值,一般是用户自己建立的索引。这里存储主键的原因是用来使用这个主键进行 回表,去聚簇索引中取出该索引列对应的完整用户记录,因为会查询两次索引,所以二级索引命名由此而来,除聚簇索引外都是二级索引,联合(多列)索引也属于二级索引的一种

MyISAM:

阅读全文 »