我们正在从MySQL迁移到PGSQL,我们有一个1亿行表.
当我试图确定两个系统使用多少空间时,我发现表的差异要小得多,但发现索引存在巨大差异.
MySQL索引比表数据本身占用更多的大小,而postgres使用的是相当小的大小.
在挖掘原因时,我发现MySQL使用B +树来存储索引,而postgres 使用 B树.
MySQL的索引使用情况略有不同,它将数据与索引一起存储(由于增加的大小),但postgres没有.
现在的问题是:
比较数据库上的B树和B +树,最好使用B +树,因为它们更适合范围查询O(m)+ O(logN) - 其中范围中的m和B +树中的查找是对数的吗?
现在在B树中,对于范围查询,查找是对数的,因为它没有数据节点的链接列表底层结构,所以它会射到O(N).话虽如此,为什么postgres使用B树?它是否适用于范围查询(确实如此,但它如何在内部处理B树)?
上面的问题来自postgres的观点,但从MySQL的角度来看,为什么它比postgres使用更多的存储,在现实中使用B +树的性能优势是什么?
我本可以错过/误解很多事情,所以请随时纠正我的理解.
编辑回答Rick James的问题
其他问题
我知道多个连接在 postgres 中使用多个 CPU 核心,因此并行运行。但是当我执行一个长时间运行的查询(比如 30 秒)(假设这不能进一步优化)时,I/O 被阻塞,并且它不会从同一客户端/连接运行任何其他查询。
这是设计使然还是可以改进?
因此,我假设运行长时间运行的查询的最佳方法是获取新连接,或者在该查询完成之前不在同一连接中运行任何其他查询?
我的目标是识别慢速查询,这可以使用慢速查询日志来完成,即将 postgresql.conf 中的超时增加到大约 100 毫秒(可接受的查询时间),然后识别慢速查询。
这有很多问题,其中之一是查询在那段时间很慢,但再次运行时速度会更快。最好的方法是获取平均值,然后处理平均较慢的查询。
这需要pg_stat_statements扩展,这应该会导致 10% 的服务器性能下降,从这里获取,该博客文章相当旧,情况可能有所改善。
我的问题
我们正在设计一个新系统,具体取决于性能,该系统将使用MySQL或Postgres。但是在进行现实的比较时会遇到一些问题。我总结了其中的一些问题,如果一些专家抛出一些问题将会很有帮助。这里的智慧。
使用中立的性能测试工具
对于postgres,有一些东西叫做“ explain analyst”,它基本上提供了在数据库方面进行优化所需的所有详细信息。但是MySQL却没有这方面的细节。
当然,这些命令提供有关单个查询的信息,实时性能涉及应用程序将如何接收的更大工作量。
这多少是真的?如果查询的postgres速度较慢,而MySQL的查询速度更快,那么相对于较重的工作负载,postgres的查询速度会更快,当然只有实时测试才能说明问题,但是值得朝这个方向发展吗?
我对Jmeter很熟悉,但是还有其他更好的工具可以完成这些任务。
两个数据库的优化
Postgres的据说是比较慢的简单的读取,但规模以及数据的增长和对更复杂workloads.Taken 这里和这里。
话虽如此,需要多少优化才能使测试对两个数据库系统都公平。
也欢迎任何其他要点。
当我们在java中创建final时,保证即使在运行时也无法更改它,因为JVM保证它.
Java类:
public class JustATest {
public final int x = 10;
}
Run Code Online (Sandbox Code Playgroud)
Javap反编译:
编译自"JustATest.java"
public class JustATest {
public final int x;
public JustATest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field x:I
10: return
}
Run Code Online (Sandbox Code Playgroud)
但是在scala中,如果我们声明a val,它会编译成一个普通的整数,并且就反编译输出而言var和val之间没有区别.
原始Scala类:
class AnTest {
val x = 1
var y = 2
}
Run Code Online (Sandbox Code Playgroud)
反编译输出:
Compiled from "AnTest.scala"
public class AnTest {
public int x();
Code:
0: aload_0
1: getfield …Run Code Online (Sandbox Code Playgroud) 当我有一个带有变量的抽象类时,如下所示
abstract class Book {
val id : Int
val name : String
val book : Long
}
Run Code Online (Sandbox Code Playgroud)
声明它们没有类型,
abstract class Book {
val id
val name
val book
}
Run Code Online (Sandbox Code Playgroud)
说错误的价值宣言.如果可以在没有显式类型注释的情况下声明方法.
abstract class Book {
val id : Int
val name : String
val book : Long
def aMethodWithNoTypeAnnotation
}
Run Code Online (Sandbox Code Playgroud)
为什么变量也不能同样有效?这是围绕JVM的限制吗?
我试图了解postgres中的锁定,这是我到目前为止所理解的.
根据我的理解,virtualxids不是真正的事务,transactionidxid是表示事务的东西.
当我做一个简单的连接到psql shell,并且我查询pg_locks表时,那里已经存在一个virtualxid.
我没有启动事务或运行查询,为什么要创建这个virtualxid?是因为这个连接可能在将来启动交易吗?
我在这里错过了什么?
在没有索引的理论场景中,带有 limit 的 order by 必须扫描所有数据,然后应用 order by,然后仅应用 limit,因为我们只有在排序后才能获取前 10 行(例如)。
但 postgres 在这方面并不聪明,下面的计划说明了这一点。
订购方式有限制
learning=# explain (analyze,buffers) select * from temp order by userid limit 10;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
Limit (cost=81745.51..81745.54 rows=10 width=41) (actual time=2064.275..2064.278 rows=10 loops=1)
Buffers: shared hit=13 read=18644
-> Sort (cost=81745.51..86735.41 rows=1995958 width=41) (actual time=2064.273..2064.274 rows=10 loops=1)
Sort Key: userid
Sort Method: top-N heapsort Memory: 25kB
Buffers: shared hit=13 read=18644
-> Seq Scan on temp (cost=0.00..38613.58 rows=1995958 width=41) (actual time=35.053..1652.660 rows=1995958 loops=1)
Buffers: shared hit=10 read=18644 …Run Code Online (Sandbox Code Playgroud) 我知道postgres使用LRU /时钟扫描算法从缓存中驱逐数据,但很难理解它如何进入shared_buffers.
请注意,我的目的不是让这个天真的查询更快,索引总是最好的选择.但我想了解缓存如何在没有索引的情况下工作.
让我们从示例中获取以下查询执行计划(我故意不包含/创建索引)
performance_test=# explain (analyze,buffers) select count(*) from users;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
Aggregate (cost=48214.95..48214.96 rows=1 width=0) (actual time=3874.445..3874.445 rows=1 loops=1)
Buffers: shared read=35715
-> Seq Scan on users (cost=0.00..45714.96 rows=999996 width=0) (actual time=6.024..3526.606 rows=1000000 loops=1)
Buffers: shared read=35715
Planning time: 0.114 ms
Execution time: 3874.509 ms
Run Code Online (Sandbox Code Playgroud)
我们可以看到所有数据都是从磁盘中获取的,即共享读取= 35715.
现在,如果我们再次执行相同的查询.
performance_test=# explain (analyze,buffers) select count(*) from users;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Aggregate (cost=48214.95..48214.96 rows=1 width=0) (actual time=426.385..426.385 rows=1 loops=1)
Buffers: shared hit=32 read=35683
-> Seq Scan on users (cost=0.00..45714.96 rows=999996 …Run Code Online (Sandbox Code Playgroud) 我正在学习scala,并且对案例类的哈希码部分感到困惑.
据我所知,case类提供了toString,equals和hashCode的自动生成.
在java中,传统观点认为java hashcode使用本机实现.
但在scala中它使用杂音哈希
我的问题.
1)Java具有本机哈希码,因为哈希码是依赖于机器的,但是如果scala使用杂音哈希那么它是如何与机器无关的?
2)Scala有常规类和案例类,普通类也使用杂音哈希吗?
3)如果murmur hash真的是第1点之后最快的实现那么为什么java仍然使用本机实现?
我正在学习函数式编程,我能理解为什么不变性比可变对象更受欢迎。
这篇文章也解释的很好。
但我无法理解为什么应该在纯函数内部执行赋值。
我能理解的一个原因是变量可变性导致锁定,因为在 Scala 中的纯函数中,我们主要是尾递归,这会在调用堆栈而不是堆上创建变量/对象。
在函数式编程中应该避免变量赋值还有什么其他原因。
我知道lazy val并且代码仅在调用时才进行评估,但我无法理解惰性和 var 的某些内容。
我正在使用的Scala版本:Scala 2.12.0
它说只有值定义才允许惰性。我在这里有点困惑,scala 中不是所有东西都是值吗?var 只是一个关键字,它与类型有关。
我可以理解applyscala中的方法,该方法主要是将函数应用于值。在许多情况下,它被用作构造函数的一种形式。
假设这list是一张地图。一个示例是def apply(id : Int) = list(id),它从列表中获取给定元素。
我也遇到了更新方法的例子
def update(id:Int,name:String) = list = list + (id -> name)。
我可以理解它的作用,即它会在列表中更新/添加一个键值对。我无法理解的是,该方法包含两个=符号,一个在方法定义之后,另一个在列表之后,定义方法的实际作用list + (id -> name)。
两个=标志有什么需要?彼此之间有何不同?我知道=在方法主体启动后,但这令人困惑。
postgresql ×7
scala ×6
performance ×5
database ×4
java ×3
jvm ×2
mysql ×2
b-tree ×1
b-tree-index ×1
caching ×1
hash ×1
sql ×1
transactions ×1