찾다
데이터 베이스MySQL 튜토리얼探索MySQL源代码之SQL历险记

探索MySQL源代码之SQL历险记

Jun 07, 2016 pm 04:05 PM
mysqlsql탐구하다소스 코드

本文从一个select语句的执行过程出发,遍历MySQL的多个几子系统。 先放图一张, 按图索骥开始我们的历险. 当客户端连接上MySQL服务端之后,发出请求之前,服务端的线程是阻塞在do_command(sql/parse.cc)里的my_net_read函数中(就是socket里的read). 当客户端键

本文从一个select语句的执行过程出发,遍历MySQL的多个几子系统。

先放图一张, 按图索骥开始我们的历险.

当客户端连接上MySQL服务端之后,发出请求之前,服务端的线程是阻塞在do_command(sql/parse.cc)里的my_net_read函数中(就是socket里的read).

当客户端键入sql语句(本文例子select * from zzz)发送到服务端之后, my_net_read返回, 并从tcpbuffer中读取数据写入到packet这个字符串.

<ol class="dp-sql"><li class="alt"><span><span>packet_length= my_net_read(net); </span></span></li></ol>

packet的第一个字节是个标志位, 决定数据包是查询还是命令,成功,或者出错。

接下来就进入dispatch_command(sql/sql/parse.cc)这个函数, 数据类型不再需要.

<ol class="dp-sql"><li class="alt"><span><span>return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); </span></span></li></ol>

进入dispatch_command, 我们可见

<ol class="dp-sql"><li class="alt"><span><span>statistic_increment(thd->status_var.questions, &LOCK_status); </span></span></li></ol>

这个就是show status questions的值累加.

接下的mysql_parse(sql/sql_parse.cc), 该函数是sql语句解析的总路口.

进入该函数后首先碰到的是query_cache_send_result_to_client,故名思义这个函数是在QCache里查询是否有相同的语句, 有则立即从QCache返回结果, 于是整个sql就结束了.

QCache里不存在的sql则继续前进来到parse_sql(sql/sql_parse.cc),这个函数主要就是调用了MYSQLparse. 而MYSQLparse其实就是bison/yacc里的yyparse(^_^),

<ol class="dp-sql"><li class="alt"><span><span>#define yyparse MYSQLparse </span></span></li></ol>

是的开始解析sql了. 关于词法分析和语法匹配简单说几下.

对于一条像select * from zzz的语句首先进入词法分析,找到2个token(select, from), 然后根据token进行语法匹配, 规则在sql/yacc.yy里, 我把几个匹配到的pattern和action贴出来.

<ol class="dp-sql">
<li class="alt"><span><span class="keyword">select</span><span>: </span></span></li>
<li><span>select_init </span></li>
<li class="alt"><span>{ </span></li>
<li><span>LEX *lex= Lex; </span></li>
<li class="alt"><span>lex->sql_command= SQLCOM_SELECT; </span></li>
<li><span>} </span></li>
<li class="alt"><span>; </span></li>
<li><span>/* Need select_init2 <span class="keyword">for</span><span> subselects. */ </span></span></li>
<li class="alt"><span>select_init: </span></li>
<li><span>SELECT_SYM select_init2 </span></li>
<li class="alt"><span>| <span class="string">'('</span><span> select_paren </span><span class="string">')'</span><span> union_opt </span></span></li>
<li><span>; </span></li>
<li class="alt"><span>select_paren: </span></li>
<li><span>SELECT_SYM select_part2 </span></li>
<li class="alt"><span>{ </span></li>
<li><span>LEX *lex= Lex; </span></li>
<li class="alt"><span>SELECT_LEX * sel= lex->current_select; </span></li>
<li><span>..... </span></li>
<li class="alt"><span>select_from: </span></li>
<li><span><span class="keyword">FROM</span><span> join_table_list where_clause group_clause having_clause </span></span></li>
<li class="alt"><span>opt_order_clause opt_limit_clause procedure_clause </span></li>
<li><span>{ </span></li>
<li class="alt"><span><span class="keyword">Select</span><span>->context.table_list= </span></span></li>
<li><span><span class="keyword">Select</span><span>->context.first_name_resolution_table= </span></span></li>
<li class="alt"><span>(TABLE_LIST *) <span class="keyword">Select</span><span>->table_list.</span><span class="keyword">first</span><span>; </span></span></li>
<li><span>} </span></li>
<li class="alt"><span>.... </span></li>
<li><span>select_item_list: </span></li>
<li class="alt"><span>select_item_list <span class="string">','</span><span> select_item </span></span></li>
<li><span>| select_item </span></li>
<li class="alt"><span>| <span class="string">'*'</span><span> </span></span></li>
<li><span>{ </span></li>
<li class="alt"><span>THD *thd= YYTHD; </span></li>
<li><span>Item *item= new (thd->mem_root) </span></li>
<li class="alt"><span>Item_field(&thd->lex->current_select->context, </span></li>
<li><span><span class="op">NULL</span><span>, </span><span class="op">NULL</span><span>, </span><span class="string">"*"</span><span>); </span></span></li>
<li class="alt"><span>if (item == <span class="op">NULL</span><span>) </span></span></li>
<li><span>MYSQL_YYABORT; </span></li>
<li class="alt"><span>if (add_item_to_list(thd, item)) </span></li>
<li><span>MYSQL_YYABORT; </span></li>
<li class="alt"><span>(thd->lex->current_select->with_wild)++; </span></li>
<li><span>} </span></li>
<li class="alt"><span>; </span></li>
<li><span>select_item: </span></li>
<li class="alt"><span>remember_name select_item2 remember_end select_alias </span></li>
<li><span>{ </span></li>
<li class="alt"><span>THD *thd= YYTHD; </span></li>
<li><span>DBUG_ASSERT($1 </span></li>
<li class="alt"><span>if (add_item_to_list(thd, $2)) </span></li>
<li><span>MYSQL_YYABORT; </span></li>
<li class="alt"><span>if ($4.str) </span></li>
<li><span>... </span></li>
</ol>

可以看到action里最关键的就是add_item_to_list 和table_list的赋值.

解析后对于需要查询的表(zzz)和字段(*)这些信息都写入到thd->lex这个结构体里了.

例如其中thd->lex->query_tables就是表(zzz)的状况, thd->lex->current_select->with_wild 是表示该语句是否使用了*等等.

<ol class="dp-sql">
<li class="alt"><span><span>(gdb) p *thd->lex->query_tables </span></span></li>
<li><span>$7 = {next_local = 0x0, next_global = 0x0, prev_global = 0x855a458, db = 0x85a16b8 <span class="string">"test"</span><span>, alias = 0x85a16e0 </span><span class="string">"zzz"</span><span>, </span></span></li>
<li class="alt"><span>table_name = 0x85a16c0 <span class="string">"zzz"</span><span>, schema_table_name = 0x0, </span><span class="keyword">option</span><span> = 0x0, on_expr = 0x0, prep_on_expr = 0x0, cond_equal = 0x0, </span></span></li>
</ol>

sql解析完了, 优化呢? 别急接着往下看.

接着进入mysql_execute_command函数,这个函数是所有sql命令的总入口.

由于是这个sql是一个select, 于是execute_sqlcom_select就是我们下个要执行的函数,又然后进入了mysql_select(^_^怒了如此复杂).

mysql_select 就是优化器的模块, 这个模块代码比较复杂. 我们可以清楚看到创建优化器,优化,执行的3个步骤, 优化细节不表.

<ol class="dp-sql">
<li class="alt"><span><span>if (!(</span><span class="op">join</span><span>= new </span><span class="op">JOIN</span><span>(thd, fields, select_options, result))) </span></span></li>
<li><span>... </span></li>
<li class="alt"><span>if ((err= <span class="op">join</span><span>->optimize())) </span></span></li>
<li><span>... </span></li>
<li class="alt"><span><span class="op">join</span><span>-></span><span class="keyword">exec</span><span>(); </span></span></li>
</ol>

结束了优化,我们要具体执行join->exec(),该函数实际进入的是JOIN::exec()(sql_select.cc)。

exec()首先向客户端发送字段title的函数send_fields, 没数据但字段也是要的。

然后再进入do_select(),根据表的存储引擎跳入到引擎具体的实现(zzz是myisam表)。

这里mi_scan就是myisam引擎扫描文件的函数,再看到

<ol class="dp-sql">
<li class="alt"><span><span>(gdb) p info->filename </span></span></li>
<li><span>./test/zzz </span></li>
</ol>

这不就是zzz表对应的物理文件吗。

通过一系列的mi函数访问磁盘拿到数据之后,会通过send_data发送数据给client,并从dispatch_command返回.最后在net_end_statement结束整个sql。

一个简单的select语句背后的执行过程是非常复杂的,上面的步骤都只是点到就止。

ps: 在sql_yacc.yy可见MySQL对于Oracle中常用的dual表的嘲讽。


성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
MySQL의 역할 : 웹 응용 프로그램의 데이터베이스MySQL의 역할 : 웹 응용 프로그램의 데이터베이스Apr 17, 2025 am 12:23 AM

웹 응용 프로그램에서 MySQL의 주요 역할은 데이터를 저장하고 관리하는 것입니다. 1. MySQL은 사용자 정보, 제품 카탈로그, 트랜잭션 레코드 및 기타 데이터를 효율적으로 처리합니다. 2. SQL 쿼리를 통해 개발자는 데이터베이스에서 정보를 추출하여 동적 컨텐츠를 생성 할 수 있습니다. 3.mysql은 클라이언트-서버 모델을 기반으로 작동하여 허용 가능한 쿼리 속도를 보장합니다.

MySQL : 첫 번째 데이터베이스 구축MySQL : 첫 번째 데이터베이스 구축Apr 17, 2025 am 12:22 AM

MySQL 데이터베이스를 구축하는 단계에는 다음이 포함됩니다. 1. 데이터베이스 및 테이블 작성, 2. 데이터 삽입 및 3. 쿼리를 수행하십시오. 먼저 CreateAbase 및 CreateTable 문을 사용하여 데이터베이스 및 테이블을 작성한 다음 InsertInto 문을 사용하여 데이터를 삽입 한 다음 최종적으로 SELECT 문을 사용하여 데이터를 쿼리하십시오.

MySQL : 데이터 저장에 대한 초보자 친화적 인 접근 방식MySQL : 데이터 저장에 대한 초보자 친화적 인 접근 방식Apr 17, 2025 am 12:21 AM

MySQL은 사용하기 쉽고 강력하기 때문에 초보자에게 적합합니다. 1.MySQL은 관계형 데이터베이스이며 CRUD 작업에 SQL을 사용합니다. 2. 설치가 간단하고 루트 사용자 비밀번호를 구성해야합니다. 3. 삽입, 업데이트, 삭제 및 선택하여 데이터 작업을 수행하십시오. 4. Orderby, Where and Join은 복잡한 쿼리에 사용될 수 있습니다. 5. 디버깅은 구문을 확인하고 쿼리를 분석하기 위해 설명을 사용해야합니다. 6. 최적화 제안에는 인덱스 사용, 올바른 데이터 유형 선택 및 우수한 프로그래밍 습관이 포함됩니다.

MySQL 초보자가 친숙합니까? 학습 곡선 평가MySQL 초보자가 친숙합니까? 학습 곡선 평가Apr 17, 2025 am 12:19 AM

MySQL은 다음과 같은 초보자에게 적합합니다. 1) 설치 및 구성이 쉽고, 2) 풍부한 학습 리소스, 3) 직관적 인 SQL 구문, 4) 강력한 도구 지원. 그럼에도 불구하고 초보자는 데이터베이스 디자인, 쿼리 최적화, 보안 관리 및 데이터 백업과 같은 과제를 극복해야합니다.

SQL은 프로그래밍 언어입니까? 용어를 명확하게합니다SQL은 프로그래밍 언어입니까? 용어를 명확하게합니다Apr 17, 2025 am 12:17 AM

예, sqlisaprogramminglanguages-pecializedfordatamanagement.1) 그것은 초점을 맞추고, 초점을 맞추고, 초점을 맞추고, sqlisessentialforquerying, 삽입, 업데이트 및 adletingdataindataindationaldatabase.3) weburer infriendly, itrequires-quirestoamtoavase

산성 특성 (원자력, 일관성, 분리, 내구성)을 설명하십시오.산성 특성 (원자력, 일관성, 분리, 내구성)을 설명하십시오.Apr 16, 2025 am 12:20 AM

산성 속성에는 원자력, 일관성, 분리 및 내구성이 포함되며 데이터베이스 설계의 초석입니다. 1. 원자력은 거래가 완전히 성공적이거나 완전히 실패하도록합니다. 2. 일관성은 거래 전후에 데이터베이스가 일관성을 유지하도록합니다. 3. 격리는 거래가 서로를 방해하지 않도록합니다. 4. 지속성은 거래 제출 후 데이터가 영구적으로 저장되도록합니다.

MySQL : 데이터베이스 관리 시스템 대 프로그래밍 언어MySQL : 데이터베이스 관리 시스템 대 프로그래밍 언어Apr 16, 2025 am 12:19 AM

MySQL은 데이터베이스 관리 시스템 (DBMS) 일뿐 만 아니라 프로그래밍 언어와 밀접한 관련이 있습니다. 1) DBMS로서 MySQL은 데이터를 저장, 구성 및 검색하는 데 사용되며 인덱스 최적화는 쿼리 성능을 향상시킬 수 있습니다. 2) SQL과 같은 ORM 도구를 사용하여 Python에 내장 된 SQL과 프로그래밍 언어를 결합하면 작업을 단순화 할 수 있습니다. 3) 성능 최적화에는 인덱싱, 쿼리, 캐싱, 라이브러리 및 테이블 부서 및 거래 관리가 포함됩니다.

MySQL : SQL 명령으로 데이터 관리MySQL : SQL 명령으로 데이터 관리Apr 16, 2025 am 12:19 AM

MySQL은 SQL 명령을 사용하여 데이터를 관리합니다. 1. 기본 명령에는 선택, 삽입, 업데이트 및 삭제가 포함됩니다. 2. 고급 사용에는 조인, 하위 쿼리 및 집계 함수가 포함됩니다. 3. 일반적인 오류에는 구문, 논리 및 성능 문제가 포함됩니다. 4. 최적화 팁에는 인덱스 사용, 선택*을 피하고 한계 사용이 포함됩니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

WebStorm Mac 버전

WebStorm Mac 버전

유용한 JavaScript 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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