meowrain

MeowRain

Life is Simple

Mysql最左匹配原则

https://blog.csdn.net/sinat_41917109/article/details/88944290?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param 什么是最左匹配原则 最左列必须出现在查询条件中 可以选择性地查询后续列,但必须按顺序 为什么前缀能利用索引,但是后缀和中缀不能使用索引? 这是因为索引的工作方式决定了它如何与不同类型的 LIKE 查询进行配合。MySQL 的 B+ 树索引(常用于字符类型的列)按照字典顺序存储数据并进行查找。让我们一步一步深入理解为什么前缀匹配能利用索引,而后缀和中缀匹配则不能。 1. 前缀匹配可以利用索引: 假设我们有如下索引: 1 CREATE INDEX idx_location ON School(location); B+ 树索引的结构是有序的,它可以高效地根据 前缀 查找数据。当你使用 LIKE 'C%' 这样的查询时,MySQL 会直接利用索引扫描,以字典顺序从 C 开始查找所有以 C 开头的字符串,直到找到不以 C 开头的字符串。B+ 树非常适合这种范围查询。 具体来说: LIKE 'C%' 会查询所有以 C 开头的字符串。 B+ 树索引能高效地查找所有符合条件的值,并快速定位到起始位置,继而返回符合条件的记录。 索引利用: 查询时,MySQL 只需要根据 location 字段的索引定位到 C,然后顺着索引查找匹配的记录。这个过程是线性的,但由于数据有序,所以查找速度非常快。 2. 后缀匹配和中缀匹配无法使用索引: 后缀匹配: 假设查询是 LIKE '%ia',这个查询需要查找以 ia 结尾的所有字符串。由于 % 出现在字符串的开头,MySQL 无法通过索引的有序特性来帮助定位。具体原因是: B+ 树索引是按照顺序排列的,查询条件是 LIKE '%ia',意味着我们不知道字符串的开始部分是什么,所以 MySQL 需要从每一个字符串的末尾进行匹配。 索引不能直接“倒着”查找,它只能按照从左到右的顺序进行查找,因此必须遍历整个表来匹配 '%ia'。 由于没有固定的开始部分,MySQL 就无法通过索引来高效过滤数据,只能进行 全表扫描。 中缀匹配: 类似于后缀匹配,查询 LIKE '%li%' 查找包含 li 的所有字符串。这个查询也是无法利用索引的,因为:

Big库处理大数字

在日常的开发过程中,不可避免的需要使用到超过变量类型的数值计算,在 go 语言中,int64 类型的变量的储存范围是 -9223372036854775808 ~ 9223372036854775807,当我们需要计算的数值大于这个范围之后,计算出的结果就会出错,这时候就需要使用到 go 语言中专门为大数计算而存在的标准库:math/big 包里面的内容。 比如 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import ( "fmt" "math" ) func main() { a := math.MaxInt64 b := math.MaxInt64 c := a + b fmt.Printf("%d + %d = %d", a, b, c) } 可以看出两个最大值的相加结果异常,这是因为两个最大值相加的结果超出了 int64 能够存储的范围。 math/big 如果需要进行上面这样的大数计算,可以使用 go 语言自带的 math/big 包进行计算,big 包中包含了整形 int 和浮点型 float 的大数计算。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main import ( "fmt" "math" "math/big" ) func main() { a := big.

B+树Go实现

B+树动画演示 https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 package main /* B+树动画演示 https://www.

Golang并发原语sync.Pool

Golang 基本同步原语 sync.Pool sync.Pool 是 Go 标准库 sync 包中的一个结构,用于管理一组可重用的对象池。通过复用对象,减少内存分配和垃圾回收的开销,从而提升程序的性能和效率。以下是对 sync.Pool 的详细讲解,包括其使用案例和使用场景。 sync.Pool 的大小是可伸缩的,高负载时会动态扩容,存放在池中的对象如果不活跃了会被自动清理。 1. sync.Pool 的功能和作用 sync.Pool 主要用于在多个 goroutine 之间高效地共享和重用临时对象。它通过保持一个池子,存储已经分配但当前不使用的对象。当需要新的对象时,首先从池子中获取,如果池子中没有可用的对象,则创建新的对象。使用完成后,将对象归还池子,以便后续复用。 sync.Pool 的主要优势在于减少内存分配和垃圾回收的开销,尤其在需要频繁创建和释放临时对象的场景下,能够显著提升程序的性能。 2.sync.Pool 核心方法 sync.Pool 提供了以下几个核心方法: New() 1 2 3 4 5 6 pool := &sync.Pool{ New: func() interface{} { // 返回一个新的对象 return new(Object) }, } 作用:初始化一个新的 sync.Pool 实例,New 是一个工厂函数,用于创建池子中对象的工厂方法。 场景:当池子中没有可用对象时,会调用 New 方法创建新的对象。 Get() 1 obj := pool.Get() 作用:从池子中获取一个可用的对象。如果池子中有对象,直接返回;如果没有,调用 New 方法创建新的对象。 返回值:返回一个 interface{} 类型的对象,需要进行类型断言。 Put() 1 pool.Put(obj) 作用:将一个对象归还到池子中,供后续复用。 注意:归还的对象应该处于初始状态,避免残留数据导致潜在的数据竞争或不一致问题。 Close() 1 pool.

Golang并发原语sync.Once

Golang 基本同步原语 sync.Onece sync.Once 是 Go 语言中一个简单但强大的同步原语,用于确保某个操作在并发场景下只执行一次。它常用于延迟初始化、单例模式、全局配置加载等场景 基本用法 sync.Once 的核心方法是 Do(f func()),传入的函数 f 只会执行一次,即使多个 goroutine 同时调用 Do。 内部实现原理 sync.Once 的源码非常简洁,其核心是通过一个 uint32 类型的原子标志位(done)和一个互斥锁(m)实现的: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package sync import ( "sync/atomic" ) type Once struct { done uint32 m Mutex } func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 0 { o.

Golang并发原语sync.Cond

Golang 基础之并发基本同步原语 sync.Cond 条件变量 Cond 类型原型 1 2 3 4 5 6 7 8 9 10 type Cond struct { // L 是在观察或改变状态时保持的 L Locker // 包含过滤或未导出的字段 } ​ func NewCond(l Locker) *Cond func (c *Cond) Broadcast() func (c *Cond) Signal() func (c *Cond) Wait() Cond 实现了一个条件变量,用于等待或宣布事件发生时 goroutine 的交汇点。 在这个定义中,“事件”是指两个或更多的 goroutine 之间的任何信号,仅指事件发生了,不包含其他任何信息。 通常,你可能想要在收到某个 goroutine 信号前令其处于等待状态。 sync.Cond 是 Go 语言中用于协调多个 goroutine 的条件变量,常用于在共享资源状态变化时通知等待的 goroutine。以下是实际使用案例及详细说明: 案例:生产者-消费者模型 生产者向队列中添加数据,消费者从队列中取出数据。当队列为空时,消费者等待;当队列有数据时,生产者通知消费者。 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package main import ( "fmt" "sync" "time" ) type Queue struct { items []int cond *sync.

Golang并发(4)

Golang 并发(四) 转载自: Golang 基础之并发 goroutine(补充)前面 《Golang 基础之并发知识 (二)》 章节已经和大家简单介绍 - 掘金 goroutine 是 go 中最基本的组织单位之一。 事实上,每个 go 程序至少有一个: main goroutine,当程序开始的时候,会自动创建并启动。 在几乎所有的 go 程序中,你都可能会发现自己迟早加入到一个 goroutine 中。 goroutine 对 Go 来说是独一无二的(尽管其他一些语言有类似的并发原语)。它们不是操作系统线程,它们不完全是绿色的线程(由语言运行时管理的线程),它们是更高级别的抽象,被称为协程(coroutines)。协程是非抢占的并发子程序,也就是说,它们不能被中断。 Go 的独特之处在于 goroutine 与 Go 的运行时深度整合。Goroutine 没有定义自己的暂停或再入点; Go 的运行时观察着 goroutine 的行为,并在阻塞时自动挂起它们,然后在它们变畅通时恢复它们。在某种程度上,这使得它们可以抢占,但只是在 goroutine 被阻止的地方。它是运行时和 goroutine 逻辑之间的一种优雅合作关系。 因此,goroutine 可以被认为是一种特殊的协程。 协程,因此可以被认为是 goroutine 的隐式并发构造,但并发并非协程自带的属性:某些东西必须能够同时托管几个协程,并给每个协程执行的机会,否则它们无法实现并发。当然,有可能有几个协程按顺序执行,但看起来就像并行一样,在 Go 中这样的情况比较常见。 Go 的宿主机制实现了所谓的 M:N 调度器,这意味着它将 M 个绿色线程映射到 N 个系统线程。 goroutine 随后被安排在绿色线程上。 当我们拥有比绿色线程更多的 goroutine 时,调度程序处理可用线程间 goroutine 的分布,并确保当这些 goroutine 被阻塞时,可以运行其他 goroutine。

Golang并发(3)

Golang 并发 (三) 基本同步原语 Go 语言在 sync 包中提供了用于同步的一些基本原语,包括常见的互斥锁 Mutex 和读写互斥锁 RWMutex 以及 Once,WaitGroup.这些基本原语的主要作用是提供较为基础的同步功能 Mutex Mutex 是 golang 标准库的互斥锁,主要用来处理并发场景下共享资源的访问冲突问题。 Mutex 互斥锁在 sync 包中,它由两个字段 state 和 sema 组成,state 表示当前互斥锁的状态,而 sema 真正用于控制锁状态的信号量,这两个加起来只占 8 个字节空间的结构体就表示了 Go 语言中的互斥锁。 1 2 3 4 type Mutex struct { state int32 sema uint32 } 互斥锁的作用,就是同步访问共享资源。互斥锁这个名字来自互斥(mutual exclusion)的概念,互斥锁用于在代码上创建一个临界区,保证同一个时间只有一个 goroutine 可以执行这个临界区代码。 不使用互斥锁: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package main import ( "fmt" "sync" ) var ( counter int wg sync.

Golang并发(2)

Golang 并发(二) 参考 链接:https://juejin.cn/post/7075723579303657485 GMP 模型 Goroutine 是 Go 语言中的协程,实现了轻量级并发,和传统的线程相比,Goroutine 有以下特点: 轻量级 高效调度:Go 运行时在用户态进行调度,避免了频繁的上下文切换带来的开销,使得调度更加高效 GMP 模型基本概念 G: Goroutine M: Machine P: Processer Goroutine 是 Go 语言中的协程,代表一个独立的执行单元,Goroutine 比线程更加轻量级,启动一个 Goroutine 的开销非常小,Goroutine 的调度由 Go 运行时在用户态进行。 Machine: 代表操作系统的线程,实际执行 Go 代码,一个 M 可以执行多个 Goroutine,但是同一时间只能执行一个 Goroutine。M 和操作系统的线程直接对应,Go 运行时通过 M 来利用多核 CPU 的并行计算能力。 Processer: P 代表执行上下文,管理者可运行的 Goroutine 队列,并且负责和 M 进行绑定,P 的数量决定了可以并行执行 Goroutine 的数量。Go 运行时会根据系统的 CPU 核数设置 P 的数量。 在 GMP 模式中,线程是物理生产者,调度器会将 goroutine 分派给一个线程。 说明: 全局队列:要执行 goroutines 的队列 P 本地队列: 和全局队列一样,它包含要执行的 goroutine,但是这个队列的最大容量是 256.

Golang并发(1)

Golang 并发(一) Golang 基础之并发知识 (一)大家好,今天将梳理出的 Go 语言并发知识内容,分享给大家。 请多多指教,谢谢。 本次 - 掘金 什么是并发,并行 什么是原子操作 原子操作可以理解为: 在进行过程中不能被中断的操作 也就是说,针对某个值的原子操作在被进行的过程中,CPU 绝不会再去进行其它针对该值的操作,无论这些其它的操作是否为原子操作都会是这样 为了实行这样的严谨性,原子操作仅会由一个独立的 CPU 指令代表和完成,只有这样才能够在并发环境下保证原子操作的绝对安全。 Go 语言提供的原子操作都是非侵入式的,它们由标准库代码包 sync/atomic 中的众多函数代表 什么是并发锁 如果两个或者多个线程在没有互相同步的情况下,访问某个共享的资源,并且试图同时读和写这个资源,就处于互相竞争的状态,这种情况被称为 race condition 也就是竞态。 竞态状态的存在是让并发程序变得复杂的地方,十分容易引起潜在问题。 对于一个共享资源的读和写必须是原子化,可以理解为,同一时刻只能有一个线程对共享资源进行读和写的操作。 一种防止竞态状态的方法,就是使用锁机制,锁住共享资源,保证线程的同步状态。 什么是通道 Go 提供了一种称为通道的机制,通道(chan)是 goroutine 之间传递特定值的通信机制,用于在 goroutine 之间共享数据。当作为 goroutine 执行并发活动时,需要在 goroutine 之间共享资源或数据,通道充当 goroutine 之间的管道并提供一种机制来保证同步交换。 它属于 通信顺序进程并发模式(Communicating sequential processes,CSP) 。 Go 语言中还有另一种并发模式,即共享内存多线程的传统模型 MPG。
0%