小觑数据库(SqlServer)查询语句执行过程
近年来,越来越多的NoSql产品不断的以技术革命的者的身份跳出来:你看哥是多么的快,你们关型型数据库真是战五渣阿。是的,高性能的场景下NoSql真的很出彩。而我们关系型数据库只能在墙角哭泣"是的,没错,他们真的好快。 但是他们为啥哪么快?用了 雷政富光环
近年来,越来越多的NoSql产品不断的以技术革命的者的身份跳出来:“你看哥是多么的快,你们关型型数据库真是战五渣阿”。是的,高性能的场景下NoSql真的很出彩。而我们关系型数据库只能在墙角哭泣"是的,没错,他们真的好快”。
但是他们为啥哪么快?用了雷政富光环了吗?我们从了解数据库引挚执行过程来了解一些基础知识,看看我们关系型数据库到底慢在哪?我只粗懂一些SqlServer,只能从SqlServer讲起。但是SQLServer是一个非常复杂的软件。我们将通过一个查询的执行过程让你对SQlServer的核心引挚和运行过程做一个简单的了解。
由于Select语句和Update语句基本一样,但是Update涉及到修改语句,所以我们直接从一条Sql语句开讲。update 码农表 set 女友=1 where 女友=0
当我们码农写下这样一条Sql,小手轻按F5。 一个女朋友就产生了 一条语句在客户端被以TDS(Tabular Data Stream)协议形式中发给SqlServer服务端的网络接口(SQL Server Network Interface)。 什么是TDS协议这不重要。 因为TDS是一个专属协议,最早由Sysbase公司设计用于与数据库服务交互。你无须过多关心。SNI是一个 协议层用于在服务端和客户端建立网络连接,自SqlServer2005以后才有。它由一系列同时使用API组成。
这些都不是我们要讲的重点,我们接着往下说。SNI收到TDS包解包后发现,哟,小子又提交Sql语句了。就将这个包标识为一个Sql命令,将此Sql命令发给命令解析器 command parser。 command Parser首先检查语法错误,如果发现语法错误,将错误通过协议层发回给客户端。如果语法验证通过,则会生成查询树。
查询树生成以后,SqlServer要进行一个非常消耗CPU的工作,就是根据查询树生成查询计划。SqlServer 并不是简单的将一个查询树翻译成查询计划,而是经过不断的比较和权衡。一条SqlServer可能有很多种查询计划.比如Select Name from table where a=1
如果这个表上没有任何索引,那么可能生成的查询计划就是表扫描。如果在A列上有索引,那么可能应用A列上的索引,也可能不用。总之,SqlServer比较各种方案找到一个开销最小的执行计划。而这个找到最小执行计划的过程,也是比较消耗CPU资源的。
为了更加有效的利用资源,SqlServer会对查询计划行缓存。将之前执行过的查询计划保存在内存中反复使用。 这里有个很有意思的性能优化点。因为内存对SqlServer来说也是非常重要的。如果缓存了大量的查询计划也会影响到SqlServer性能。那么不缓存费CPU,缓存费内存。我们该怎么办?我们应该更加高效的利用查询计划缓存。举个例子。刚才我们执行的语句update 码农表 set 女友=1 where 女友=0
然后又执行 update 码农表 set 女友=0 where 女友=1
对于SqlServer来说,它会把这当成二条完全不同的语句来处理。
这里有一个定义:以单独的SQL语句的形式执行的查询就是即席查询(Adhoc)。我们经常在程序里拼的sql,就是这种既席查询。
如果你的系统中有大量的既席查询,会产生大量查询计划缓存。所以推荐大家在程序中写Sql时,尽量的使用参数化。update 码农表 set 女友=1 where 女友=@女友数
既高效又防Sql注入,何乐而不为呢?
到上面为止,完成这些工作的组件都属于Sqlserver的关系引挚部分。关系查询可以说是SqlServer中最复杂的组件。用于确定查询的最佳执行方案。而市面上大多NoSql数据库没有关系引挚这部分。语句处理比较简单。 这就节约了一部分开销。
而数据的访问和管理则由存储引擎负责。事实上我也不算说存储引挚部分的细节。我们只谈谈关系型数据库和NoSql不太一样的部分。SqlServer和大多数NoSql数据库一样,都是非常依赖内存的。内存比磁盘快。这是人所共知的。 SqlServer也有将数据缓存中内存中的机制。每次查询请求数据时 SqlServer先在在内存中查询有没有对应的页。 这里的页是指一个段连续的8KB内存。这段内存是将数据库文件中的页(每个页8KB)直接映射到内存中的。如果发现有查询需要的页将直接将对应的页的内容打包成结果返回。如果没有,SqlServer则先去磁盘中找到对应的页将它载入内存。再将内存中的页返回。而查询结束,内存中的页也不在回收。将一直保存到内存中。直到SqlServer发现操作系统可用内存不足,才会将一些不常使用的内存页还给操作系统(多聪明)。而且SqlServer会预先分配一些空白的内存页。这样等到用时就不用现分配了。 知道了上面原理,你就能明白 为什么Page Life Expectancy (PLE) 性能记数器的数值越大越好了。Page Life Expectancy (PLE) 越大表示一个页面在内存在呆的时间越长。也就是说你的内存压力越小。
可是,如果要是更新时SqlServer怎么办?我们知道关系型数据库对持久性的要求比好多NoSql产品都有节操多了。那数据库是如何保证持久性(喂不要想太多)和尽量提高性能的呢?
SqlServer使用了一种叫预写式日志的技术。简单来说就是你不是叫我干活吗?活还没干呢,我先把我要干的活写下来。然后等我有空时再干活。这么做有什么好处呢?
首先,我们知道磁盘的随机写入性能是很低的,相反,顺序写入性能要比随机写入高很多。如果每次用户更新数据时,都写入到数据库文件,那么很有可能产生一个随机读写。这样可能会影响性能。而SqlServer采用的是先写入日志。然后只更新内存中的对应的数据页。而日志一般都是顺序写入文件尾部的。这样一次随机的读写就被转换成一次顺序写加一次内存修改。性能自然有效提升。 而一般的NoSql数据库默认情况下并不保证写入的持久性。有的是定时刷到硬盘,但是并没有预写式日志,有的是先让你返回,成功不成功你再来问一次。
那SqlServer又是如何保证内存中的数据被回写到硬盘呢?SqlServer和上面提到有些NoSqL有点类型。SqlServer有一个叫 Lazy Writer 线程,用于周期的检测 空闲缓存页的值,如果这个值较低,他将扫描正个数据缓存将较长时间没有没使用的页面过期。如果他发现一个很长时间没有被使用的脏页,他也会将被更的页面但还没有回写到硬盘的页–也叫脏页写入到磁盘,并将他在内存中标记为空闲页。
那如果SqlServer突然断电,而内存中的脏页并没有来得及写入到硬盘肿么办?SqlServer使用一种叫检查点的机制。
检查点进程确保任何和已提交事务相关的脏页能被写入到磁盘,也将未提交事务的脏页写入磁盘以确保效率。和Lazy Writer 不同,检点查并不将页面移出缓存。他只是将脏页刷入磁盘,然后页面头标识这个页面为 Clean Page。 默认情况下,在一个忙碌的服务器上,SQL Server 大约每一分钟发起一个检查点并记录在事务日志里。如果SqlServer 实现或数据库重新启动,那么恢复进程通过读取事务日志就知道那些工作是在检查点之前做的。检查点之前做的工作,他不用理会。注意:CheckPoint的触发条件,是在CheckPoint期间生成日志的大小。因此,大家见过内存中有很多脏页,却不引发CheckPoint的情况。
当SQL Server非正常原因关闭时,也就是在没有走CheckPoint(会在下面提到)时关闭了数据库,此时数据库中数据本身可能存在不一致的问题。因此在数据库再次启动的时候,会去扫描日志,找出那些未提交却写入持久化存储的数据,或已提交却未写入持久化存储的数据,来进行Undo和Redo来保证事务的一致性。SqlServer 会尝试保证数据库恢复时间小于1分钟,但是,至少需要有10M数据写入日志,sQLServer才会触发CheckPorint
到这,你也就明白了为什么数据库会慢于NoSql产品了。当然这也只是我所理解的一方面。可能还有很多地方NoSql有优化的地方。如果简化掉关系引挚,去掉预写式日志,数据库性能会不会也有质的飞跃呢?可这一切又值得吗?
另外,如果你的数据文件和日志如果在一个磁盘上,那个可能这个预入式日志优势会大打折扣。原因你一定想的到。
其实我只是借这NoSQL火抱一下大腿。这篇贴子并没有大多NoSql的内容。我对NoSql也不太了解。但是现在你不会NoSql你都当了意思和人家打招呼了。NoSql在一些对事务性要求不太高的地方大有用武之地。我打算看完硬盘里的波多老师作品就去学习Nosql
了。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

Apple의 최신 iOS18, iPadOS18 및 macOS Sequoia 시스템 릴리스에는 사진 애플리케이션에 중요한 기능이 추가되었습니다. 이 기능은 사용자가 다양한 이유로 손실되거나 손상된 사진과 비디오를 쉽게 복구할 수 있도록 설계되었습니다. 새로운 기능에는 사진 앱의 도구 섹션에 '복구됨'이라는 앨범이 도입되었습니다. 이 앨범은 사용자가 기기에 사진 라이브러리에 포함되지 않은 사진이나 비디오를 가지고 있을 때 자동으로 나타납니다. "복구된" 앨범의 출현은 데이터베이스 손상으로 인해 손실된 사진과 비디오, 사진 라이브러리에 올바르게 저장되지 않은 카메라 응용 프로그램 또는 사진 라이브러리를 관리하는 타사 응용 프로그램에 대한 솔루션을 제공합니다. 사용자는 몇 가지 간단한 단계만 거치면 됩니다.

Navicat 데이터베이스 구성 파일이 저장되는 위치는 운영 체제에 따라 다릅니다: Windows: 사용자별 경로는 %APPDATA%\PremiumSoft\Navicat\macOS: 사용자별 경로는 ~/Library/Application Support/Navicat\Linux: 사용자별 경로는 ~/ .config/navicat\입니다. 구성 파일 이름에는 navicat_mysql.ini와 같은 연결 유형이 포함되어 있습니다. 이러한 구성 파일은 데이터베이스 연결 정보, 쿼리 기록 및 SSH 설정을 저장합니다.

MySQLi를 사용하여 PHP에서 데이터베이스 연결을 설정하는 방법: MySQLi 확장 포함(require_once) 연결 함수 생성(functionconnect_to_db) 연결 함수 호출($conn=connect_to_db()) 쿼리 실행($result=$conn->query()) 닫기 연결( $conn->close())

PHP에서 데이터베이스 연결 오류를 처리하려면 다음 단계를 사용할 수 있습니다. mysqli_connect_errno()를 사용하여 오류 코드를 얻습니다. 오류 메시지를 얻으려면 mysqli_connect_error()를 사용하십시오. 이러한 오류 메시지를 캡처하고 기록하면 데이터베이스 연결 문제를 쉽게 식별하고 해결할 수 있어 애플리케이션이 원활하게 실행될 수 있습니다.

Navicat 연결 URL의 형식은 다음과 같습니다: 프로토콜://사용자 이름:비밀번호@호스트:포트/데이터베이스 이름? 프로토콜, 사용자 이름, 비밀번호, 호스트 이름, 포트, 데이터베이스 이름 및 선택 사항을 포함하여 연결에 필요한 정보를 포함하는 매개변수입니다. 매개변수.

Golang의 데이터베이스 콜백 기능을 사용하면 다음을 달성할 수 있습니다. 지정된 데이터베이스 작업이 완료된 후 사용자 정의 코드를 실행합니다. 추가 코드를 작성하지 않고도 별도의 함수를 통해 사용자 정의 동작을 추가할 수 있습니다. 삽입, 업데이트, 삭제, 쿼리 작업에 콜백 함수를 사용할 수 있습니다. 콜백 함수를 사용하려면 sql.Exec, sql.QueryRow, sql.Query 함수를 사용해야 합니다.

JSON 데이터는 gjson 라이브러리 또는 json.Unmarshal 함수를 사용하여 MySQL 데이터베이스에 저장할 수 있습니다. gjson 라이브러리는 JSON 필드를 구문 분석하는 편리한 방법을 제공하며, json.Unmarshal 함수에는 JSON 데이터를 비정렬화하기 위한 대상 유형 포인터가 필요합니다. 두 방법 모두 SQL 문을 준비하고 삽입 작업을 수행하여 데이터를 데이터베이스에 유지해야 합니다.

Go 표준 라이브러리 데이터베이스/sql 패키지를 통해 MySQL, PostgreSQL 또는 SQLite와 같은 원격 데이터베이스에 연결할 수 있습니다. 데이터베이스 연결 정보가 포함된 연결 문자열을 생성합니다. sql.Open() 함수를 사용하여 데이터베이스 연결을 엽니다. SQL 쿼리 및 삽입 작업과 같은 데이터베이스 작업을 수행합니다. 리소스를 해제하기 위해 defer를 사용하여 데이터베이스 연결을 닫습니다.
