查询的处理和优化
Join Operation, 连表 在查询过程中经常会涉及到连表的操作。那么为什么总是需要连表呢? ==为什么需要连表?== 在存储的时候为了避免数据的冗杂,将表进行规范化,导致表的割裂。 在查询的时候需要获取完整的信息,所以将表进行重新的组装。 连表的算法 Fetching Title#i6kq
Join Operation, 连表 在查询过程中经常会涉及到连表的操作。那么为什么总是需要连表呢? ==为什么需要连表?== 在存储的时候为了避免数据的冗杂,将表进行规范化,导致表的割裂。 在查询的时候需要获取完整的信息,所以将表进行重新的组装。 连表的算法 Fetching Title#i6kq
数值类型 整数类型 整数就是没有小数部分的数字。之前使用过的 i32 类型,表示有符号的 32 位整数( i 是英文单词 integer 的首字母,与之相反的是 u,代表无符号 unsigned 类型)。下表显示了 Rust 中的内置的整数类型: 整型溢出 在使用编程的过程中难免会发生数的范围超过了类型范围这时候就会发生溢出的现象。 有趣的是:在debug模式下编译器会检测有没有发生整形溢出的现象,如果有发生整数溢出的现象编译就会发生panic. 但是在release模式下,编译器不会进行整数溢出的的检测。当发生整数溢出的时候会按照补码循环溢出进行处理。简单来讲就是取余。 要显式的处理可能的溢出,可以使用标准库提供的类型。 使用warpping_*的方法在所有模式下都按照补码循环溢出的规则进行处理 使用check_*方法发生溢出的时候返回None值。 使用overflowing_*方法返回该值和是否溢出的一个bool值 使用saturating_*的方法返回最大值或者最小值 下面是一个演示warpping_*的一个示例代码 fn main() { let a : u8 = 255; let b = a.wrapping_add(20); println!("{}", b); // 19 } 最后这个输出结果也没有出乎意料。 浮点类型 浮点类型是带有小数点的数字。在Rust中浮点数类型也有两种表示f32,f64. 分别表示32位和64位。在现代CPU中32位的运算速度几乎和64位是一样的。所以默认是f64. 浮点数陷阱 浮点数在其底层表示上有很大的特殊性,这就导致了如果在使用的时候不够谨慎就会造成危险。主要有以下两个原因。 浮点数是一种近似的表达。由于所有的生活中的数字我们都是用十进制进行标识但是计算机用二进制在底层进行表示,所以我们很难非常准确的表示十进制的小数。 浮点数在某一些事情上是反直觉的。例如很多人都觉得浮点数是可以进行比较的对吧。但是实际上如果我们编写如下的代码会发生什么呢? fn main(){ assert!(0.1+0.2==0.3); } 程序将会panic,因为二进制精度 的问题,0.1+0.2将会在N位之后与0.3发生偏差。 为了避免掉入陷阱当中,我们需要注意以下两点。 避免在浮点数上测试相等性 当结果在数学上存在未定义的时候我们需要格外的小心 但是如果非要进行比较呢? 可以考虑用这种方式 (0.1_f64 + 0.2 - 0.3).abs() < 0.00001 ,具体小于多少,取决于你对精度的需求。 ...
一些关于为什么要学rust的想法 其实在大一的时候我就有了解过rust语言,当时甚至还看了一周b站的视频,在我最近准备再看rust的时候发现我大一装的环境还在,我甚至自己都不记得有这件事了。 rust语言据说有非常好的内存管理机制和安全措施,以及极高的执行效率,所以近些年被用作开发底层非常的多,而我对这方面也是非常的感兴趣,也算是兴趣驱动吧。希望能有助于提高一下自己的编程能力,让自己也多了解一下rust语言。
auto 在概念上auto已经极简了,但是实际上仍然要微妙许多。它可以节约声明类型,也可以避免许多手动类型的正确性和声明问题。但是从结果的角度来说,尽管auto很努力在做事了,但是仍然可能是错误的。如果出现这种情况我们要知道如何去引导auto让他成为正确的类型,因为退回使用手动声明类型仍然是下下策。 接下来的内容会涵盖auto的所有细节 Item 5: Prefer auto to explicit type declarations. 不仅可以避免出现为初始化的变量,避免啰嗦又繁杂的类型声明,能直接持有闭包,还可以避免一些因为“类型捷径”出现的问题。 eg1. 有一些程序员会对类型发生误判,到时用范围较小的类型在32位机器上能够运行但是在64位机器上发生了改变,导致程序在移植的时候出现问题。 eg2. 上述代码看起来没什么问题,但是当实际运行之后并没有对哈希表m进行操作。原因在于哈希表中的kay值是const类型的,手动声明的类型不一样的话编译器会进行一个神奇的操作,它会讲m中的内容复制成为临时变量将key的类型改为和声明一致的,再将p绑定到临时变量上。 Summary auto说到底只是一个可选项罢了,不是必选项,如果你觉得你的项目使用显式的声明能够使得项目变得更加的可读和高效,当然可以继续使用。但是c++引入auto并不是一个多新鲜的东西,只是一个在其他语言中被称为“类型推导”的东西罢了。在其他的静态类型语言中类型推导都或多或少存在。而且动态语言还为类型推导积累了大量的经验。而且此类技术并不会于大型的工程项目产生冲突。 一些人觉得用完auto之后会让变量的类型变得不是一眼可以识别,但是这个问题随着ide的优化和适配已经被解决的相当完美了。 事实上手动声明变量经常是在画蛇添足,无论是正确率还是效率上。 Item 6: Use the explicitly typed initializer idiom when auto deduces undesired types. 纵使auto有万般好,但是auto也会出现推断的类型和你心目中期待的不一样的情况(当然也不完全是auto错了哦😀) 下面举一个auto推断不符合预期的例子。 上述声明了一个返回vector< bool >类型的函数,使用了auto之后虽然仍然能够直接进行编译和运行但是结果却不是所想要的。 而发生这样错误的原因是,在c++的设计当中回避了bit的引用所以返回的不是bool&,实际上c++中设计了一个代理类来完成向bool的转换操作,这就不展开细说了,但是代理类并不少见,我们经常使用的两个智能指针就是一种代理类。 代理类的设计在使用的时候尽量少的对程序员暴露内部细节,这些代理类的使用往往会在文档中标识出来,如果在文档中没有体现的话,也避免不了在头文件中漏出一些破绽,最不济在debug的时候可能也会发觉是使用了代理类。 但是这些都不重要了,现在重要的事怎么把auto引导到正确的道路上🙃。 就是使用一个强制的类型转换,让它去到该去的位置,虽然看起来有点滑稽,给人一种头痛医脚的感觉🤣。虽然在这些时候你也可以放弃使用auto,但是在这个踩坑的过程中不是也收获了新的知识么?😁 总之记住以下两点 隐形的代理类可能会让auto推断出错误的类型。 显式的类型转换可以让auto走向正确道路。 Moving to Modern C++ 接下来这一章会详细介绍现代c++的一些细节特性。我自己会记录几个我认为比较实用的。并不是全部。 Item 8: Prefer nullptr to 0 and NULL. 非常显然的是0的类型是int,不是一个指针,但是在一个本应该出现指针类型的地方出现了0,编译器也会勉强吧0解释为空指针,但这毕竟是不得已而为之的行为🙉, 总之0是int,不是指针。 nullptr’s advantage is that it doesn’t have an integral type. To be honest, it doesn’t have a pointer type, either, but you can think of it as a pointer of all types. nullptr’s actual type is std::nullptr_t, and, in a wonderfully circular definition, std::nullptr_t is defined to be the type of nullptr. The type std::nullptr_t implicitly converts to all raw pointer types, and that’s what makes nullptr act as if it were a pointer of all types. ...
TABLE INDEX A table index is a replica of a subset of a table’s attributes that are organized and/or sorted for efficient access using those attributes.The DBMS ensures that the contents of the table and the index are logically synchronized. 索引让数据在数据库中的查询更加的高效,DBMS负责使索引和实际内容同步。 DBMS的工作是选择最优的索引去执行查询,这就带来一个需要权衡的问题——索引越多查询越高效但是相对的维护成本(Maintenance Overhead)和存储成本(Storage Overhead) 就会相应的提高。 B-TREE FAMILY B-树家族。 重点了解B+树。 (B树虽然是一个平衡树(balance),但B树的B不是balance的缩写,到底代表什么还存疑) B+TREE B+树是一个自平衡树的数据结构,顺序的存储数据,并且将查询,顺序访问,插入和删除的时间复杂度基本控制在O(log n)。 是二叉搜索树的推广,因为它可以有超过两个的孩子节点。 它针对系统和存储之间的大块数据读写进行了特别的优化。 B+TREE PROPERTIES B+树是一个多叉搜索树,有以下特性: 他完美平衡 除了根节点都至少半满 k个值会把一个节点分为k+1部分。 B+TREE EXAMPLE 上图是一个小例子,能够发现B+树底层是能够双向访问的,这在多线程的时候有可能会造成死锁问题。这在后面讲解B+树多线程的章节也会对原因进行讲解。 ...