探索MySQL源代码之SQL历险记
本文从一个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表的嘲讽。

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Sie können PhpMyAdmin in den folgenden Schritten öffnen: 1. Melden Sie sich beim Website -Bedienfeld an; 2. Finden und klicken Sie auf das Symbol phpmyadmin. 3. Geben Sie MySQL -Anmeldeinformationen ein; 4. Klicken Sie auf "Login".

MySQL ist ein Open Source Relational Database Management -System, das hauptsächlich zum schnellen und zuverlässigen Speicher und Abrufen von Daten verwendet wird. Sein Arbeitsprinzip umfasst Kundenanfragen, Abfragebedingungen, Ausführung von Abfragen und Rückgabergebnissen. Beispiele für die Nutzung sind das Erstellen von Tabellen, das Einsetzen und Abfragen von Daten sowie erweiterte Funktionen wie Join -Operationen. Häufige Fehler umfassen SQL -Syntax, Datentypen und Berechtigungen sowie Optimierungsvorschläge umfassen die Verwendung von Indizes, optimierte Abfragen und die Partitionierung von Tabellen.

Redis verwendet eine einzelne Gewindearchitektur, um hohe Leistung, Einfachheit und Konsistenz zu bieten. Es wird E/A-Multiplexing, Ereignisschleifen, nicht blockierende E/A und gemeinsame Speicher verwendet, um die Parallelität zu verbessern, jedoch mit Einschränkungen von Gleichzeitbeschränkungen, einem einzelnen Ausfallpunkt und ungeeigneter Schreib-intensiver Workloads.

MySQL wird für seine Leistung, Zuverlässigkeit, Benutzerfreundlichkeit und Unterstützung der Gemeinschaft ausgewählt. 1.MYSQL bietet effiziente Datenspeicher- und Abruffunktionen, die mehrere Datentypen und erweiterte Abfragevorgänge unterstützen. 2. Übernehmen Sie die Architektur der Client-Server und mehrere Speichermotoren, um die Transaktion und die Abfrageoptimierung zu unterstützen. 3. Einfach zu bedienend unterstützt eine Vielzahl von Betriebssystemen und Programmiersprachen. V.

Die Position von MySQL in Datenbanken und Programmierung ist sehr wichtig. Es handelt sich um ein Open -Source -Verwaltungssystem für relationale Datenbankverwaltung, das in verschiedenen Anwendungsszenarien häufig verwendet wird. 1) MySQL bietet effiziente Datenspeicher-, Organisations- und Abruffunktionen und unterstützt Systeme für Web-, Mobil- und Unternehmensebene. 2) Es verwendet eine Client-Server-Architektur, unterstützt mehrere Speichermotoren und Indexoptimierung. 3) Zu den grundlegenden Verwendungen gehören das Erstellen von Tabellen und das Einfügen von Daten, und erweiterte Verwendungen beinhalten Multi-Table-Verknüpfungen und komplexe Abfragen. 4) Häufig gestellte Fragen wie SQL -Syntaxfehler und Leistungsprobleme können durch den Befehl erklären und langsam abfragen. 5) Die Leistungsoptimierungsmethoden umfassen die rationale Verwendung von Indizes, eine optimierte Abfrage und die Verwendung von Caches. Zu den Best Practices gehört die Verwendung von Transaktionen und vorbereiteten Staten

Apache verbindet eine Verbindung zu einer Datenbank erfordert die folgenden Schritte: Installieren Sie den Datenbanktreiber. Konfigurieren Sie die Datei web.xml, um einen Verbindungspool zu erstellen. Erstellen Sie eine JDBC -Datenquelle und geben Sie die Verbindungseinstellungen an. Verwenden Sie die JDBC -API, um über den Java -Code auf die Datenbank zuzugreifen, einschließlich Verbindungen, Erstellen von Anweisungen, Bindungsparametern, Ausführung von Abfragen oder Aktualisierungen und Verarbeitungsergebnissen.

Wie verbinde ich mit PhpMyAdmin mit MySQL? Die URL zum Zugriff auf phpmyadmin ist normalerweise http: // localhost/phpmyadmin oder http: // [Ihre Server -IP -Adresse]/Phpmyadmin. Geben Sie Ihren MySQL -Benutzernamen und Ihr Passwort ein. Wählen Sie die Datenbank aus, mit der Sie eine Verbindung herstellen möchten. Klicken Sie auf die Schaltfläche "Verbindung", um eine Verbindung herzustellen.

So lösen Sie den MySQL -Zugriff für Benutzer "Fehler: 1. Überprüfen Sie die Berechtigung des Benutzers, eine Verbindung zur Datenbank herzustellen. 2. Setzen Sie das Passwort zurück; 3.. Remote -Verbindungen zulassen; 4. Erfrischungsberechtigungen; 5. Überprüfen Sie die Datenbankserverkonfiguration (Bind-Address, Skip-Grant-Tabellen). 6. Überprüfen Sie die Firewall -Regeln; 7. Starten Sie den MySQL -Dienst neu. TIPP: NACHTEN ALDEN, ABER DIE DATABASE.
