一、介绍
客户端程序和服务器程序实质上都是计算机上的一个过程,客户端过程向服务器过程发送申请的过程实质上是一种过程间通信的过程,StoneDB 数据库服务程序作为服务器程序,客户端只有遵循规定的通信协议,都能够进行连贯,包含但不限于 odbc、jdbc、.net 等。
那么,客户端连贯到 StoneDB 数据库服务程序后,向服务器发送了申请,服务器是如何解决,能力产生最初的后果。客户端能够向服务器发送增删改查等各类申请,本文以比较复杂的 查问申请为例,来展现下服务器模块解决的大抵过程,如下图:
二、连接器
客户端能够采纳 TCP/IP、命名管道、共享内存或者 UNIX 域套接字等形式与服务器连贯,每当有一个客户端连贯到服务器时,服务器都会创立一个线程与客户端建设连贯,专门与这个客户端进行交互。当客户端与服务器断开连接时,服务器不会销毁连贯的线程,会将线程回收缓存起来,等新的客户端连贯时将其唤醒应用,防止线程频繁地创立和销毁带来的开销,即连接线程池技术;
客户端在连贯服务器时,会发送主机信息、用户名、明码等信息,服务器会对这些信息进行认证,如果认证失败则会拒接连贯。
当连贯建设后,负责与客户端连贯的线程会始终循环期待客户端的音讯,收到音讯后,去进行下一步解决。
1. 性能入口
handle_connections_methods()
2. 建设连贯
反对 CP/IP 协定、UnixSocket、共享内存和命名管道形式,创立连贯胜利后,唤醒线程池中的一个线程,来解决该连贯。以上几种形式反对状况如下:
TCP/IP:反对跨平台、跨主机之间通信。
UnixSocket:反对类 Unix 零碎,同一主机上通信。
共享内存:反对 Windows 零碎,同一主机上通信。
命名管道:反对 Windows 零碎,同一主机上通信。
函数接口:
1)命名管道连贯解决线程。
handle_connections_namedpipes()
2)共享内存连贯解决线程。
handle_connections_shared_memory()
3)socket 连贯解决线程 -unix socket 和 tcp/ip 都在其中实现。
handle_connections_sockets_thread()
3. 权限认证
对主机、端口、账户和明码等进行认证。
函数接口:
check_connection()
4. 循环接管指令
与客户端交互,对 insert、update、select、delete 等指令进行解决。
代码块:
while (thd_is_connection_alive(thd))
{mysql_audit_release(thd);
if (do_command(thd))
break;
}
5. 敞开连贯
在失常敞开连贯状况下,服务检测到连贯敞开,而后开释相干资源,将线程放回线程中。
函数接口:
end_connection()
close_connection()
6. 线程池
应用线程池技术,能够防止线程反复创立和销毁带来的开销,也可在高并发的场景下,带来效率的晋升。
三、查问缓存
StoneDB 服务器程序在解决查问申请时,会把之前解决过的查问申请和查问后果缓存起来,如果下次有雷同的查问申请过去,间接从缓存中取出后果,而后返回给客户端,减少了解决效率。而且查问缓存是共享的,不同客户端连贯共享查问缓存,比方:如果客户端 A 进行了一个申请,而后客户端 B 发送了一个同样的查问申请,那么客户端 B 这次的查问申请能够间接从查问缓存中拿取返回,跳过了解析、优化和执行等阶段,进步了查问效率。
然而查问缓存既然是缓存,就有缓存生效的时候,StoneDB 数据库系统会监测缓存波及的每一张表,当其中的表的构造或者数据被批改时,那么所有与该表相干的查问缓存都会从查问缓存中删除。
值得注意得是:查问缓尽管有时候能够晋升查问效率,然而在生产环境中命中的概率不高,而且不得不为了保护查问缓存,而带来一些额定的开销,比方:查问缓存更新和生效解决,每次申请都要去查问缓存中检索等,所以不倡议应用。如果想敞开查问缓存性能,能够在 stonedb.cnf 文件中配置 query_cache_type=0 和 query_cache_size= 0 来敞开此查问缓存的应用。
1. 性能入口
query_cache_send_result_to_client()
2. 语句解决
拿到网络包数据,判断是否为 select 语句,并对语句间隙进行赋 0 解决等。
3. 缓存 hash 查问
通过 hash 查找缓存中有没有该语句的查问记录。
函数接口:
my_hash_search()
4. 权限查看
判断该用户是否具备查问该表的权限。
函数接口:
check_table_access()
然而不查看列权限,如果须要查看列权限,则退出去解析。
5. 发送命中数据
将命中的缓存数据,拆包后顺次发送给客户端。
函数接口:
send_data_in_chunks()
四、解析器
如果查问缓存未命中,则须要进入解析阶段,因为客户端发送给服务器的只是一段文本,所以 StoneDB 服务器程序首先要对这段文本进行解析,解析次要分为词法解析和语法解析。StoneDB 对将词法解析和语法解析互相联合,将本人实现的 lex 解析和开源的 yacc 相结合,生成对应的解析树。
1. 性能入口
parse_sql()
2. 词法解析
将一个残缺的 sql 语句解析成一个个单词或字符,比方:select stone,db from stonetable 会被拆分成 5 个单词,并查看 token 是否为关键字等。
函数接口:
MySQLlex()
3. 语法解析
查看 sql 语句的语法,比方 ”(“ 有没有闭合,是否遵循 StoneDB 语法规定等,最终造成一个解析树(select_lex)。
函数接口:
MYSQLparse()
4.select 权限认证
判断对相应表和列有没有 select 权限。
函数接口:
select_precheck()
五、StoneDB 引擎的优化器和执行器
再通过解析器后,失去解析树之后,还须要做预处理。然而这些是不够的,因为咱们写的 sql 语句执行起来可能并不高效,这时候就须要 StoneDB 优化器了,StoneDB 优化器会对咱们的语句做一些优化,如表达式转化、子查问转连贯等等,优化的后果就是生成一个高效的执行打算,而后 StoneDB 执行器会依据这个执行打算进行具体操作。
1. 性能入口
SDB_HandleSelect()
2. 预处理
为整个查问做预处理,包含子查问。进一步查看参数合法性,having 等条件的解决,造成更精确的计算形容,生成一个优化过的解析树。
函数接口:
prepare()
3. 优化
一个查问语句可能有多个执行计划,优化器基于独特的常识网格技术,计算出最优的查问计划。
函数接口:
optimize()
4. 执行器
依据优化器给的执行打算,施行具体操作。
函数接口:
Execute()