首页 > 数据库 > MySQL > 正文

源码下载网浅析MySQL 查询优化器

2024-07-24 12:40:36
字体:
来源:转载
供稿:网友
优化器(The Optimizer)    这篇描述MySQL查询优化器的工作原理。MySQL查询优化器主要为执行的查询决断最有效的路线(routine,走向)。       一。源代码和概念    这部分讨论优化器关键概念,术语,及在MySQL源代码怎么对应的。       1.定义    狭义定义:优化器,就是DBMS为查询时决断要往哪种执行路径的一系列路线。    MySQL是经常调整查询的路线,所以你得把这篇描述的逻辑和在源代码里的做比较。为了使比较容易些,这里会包含相关文件和路径的注解,例如源代码/sql/sql_select.cc,optimize_cond()函数。    当一个查询被转成另一种查询时,其结果是一样的,就会发生语句转化。如下这个查询   SELECT ... WHERE 5 = a 就会被转化成为   SELECT ... WHERE a = 5  最明显的语句转化是少的,有些语句转化,是为了更快的执行。       2.优化器源代码    如下伪代码显示了/sql/sql_select.cc中handle_select()函数的逻辑结构。(源代码/sql/sql_select.cc处理SQL查询)   handle_select()    mysql_select()      JOIN::prepare()        setup_fields()      JOIN::optimize()            /* optimizer is from here ... */        optimize_cond()        opt_sum_query()        make_join_statistics()          get_quick_record_count()          choose_plan()            /* Find the best way to access tables */            /* as specified by the user.          */            optimize_straight_join()              best_access_path()            /* Find a (sub-)optimal plan among all or subset */            /* of all possible query plans where the user    */            /* controls the exhaustiveness of the search.   */            greedy_search()              best_extension_by_limited_search()                best_access_path()            /* Perform an exhaustive search for an optimal plan */            find_best()        make_join_select()        /* ... to here */      JOIN::exec()  缩进行显示了哪个函数调用哪个函数,如handle_select()函数调用mysql_select()函数,mysql_select()函数会调用JOIN::prepare()、JOIN::optimize()、JOIN::exec(),以及类推。mysql_select()函数的第一部分是调用JOIN::prepare(),此函数用来上下文分析、元数据建立和一些语句转化。查询优化器函数JOIN::optimize()和其所有优化处理中的子路线。当执行完JOIN::optimize()函数后,JOIN::exec()接管并完成JOIN::optimize()函数优化决断后的执行工作。    虽然有JOIN字出现,其实查询优化器的工作会处理所有的查询类型,不单单JOIN联接查询。     二。首要优化    这部分讨论服务器执行的最重要优化。       1.优化常数关系   常数等值传递    如下的表达式会发生语句转化:   WHERE column1 = column2 AND column2 = 'x'  这种表达式,众所周知,如果A=B && B=C => A=C(可等值传递),上句表达式转化后变成:   WHERE column1='x' AND column2='x'      当且仅当,操作符为如下的任何一个,在column1 <操作符> column2条件中就会发生语句转化:   =, <, >, <=, >=, <>, <=>, LIKE 注意:等值传递的转化,不适合于BETWEEN。可能也不适合于LIKE,这是后话。        常数等值传递同样发生在循环中,前一步传递的输出作为后一步传递的输入。   源代码见/sql/sql_select.cc,change_cond_ref_to_const()函数。或/sql/sql_select.cc,propagate_cond_constants()函数。       剔除死代码    总是TRUE的条件会发生语句转化,如:   WHERE 0=0 AND column1='y' 这种情况下,第一个条件会被剔除,最后为:   column1='y'  源代码见/sql/sql_select.cc,remove_eq_conds()。        总是FLASE的条件也会发生语句转化,如:   WHERE (0 = AND s1 = OR s1 = 7 小括号和前两个条件总是FLASE,最后为:   WHERE s1 = 7      还有一些情况下,当WHERE语句中代表不可能的条件,查询优化器可能会全部剔除语句,如下:   WHERE (0 = AND s1 = 5) 因为这条件永远不为TRUE,在EXPLAIN分析中会显示Impossible WHERE。简单地说,MySQL会说WHERE条件被优化过。       如果一个字段不能为NULL,优化器会剔除所有不相关的IS NULL的条件,这样   WHERE not_null_column IS NULL 这种条件总为FLASE情况;且   WHERE not_null_column IS NOT NULL 这种条件总为TRUE情况,所以这种字段查询的条件也被剔除。这种判断是很微妙的。举个例:在一个OUT JOIN外联接,被定义成NOT NULL字段仍然含有NULL值,优化器就会单独排除IS NULL条件在这种特殊情况中。        优化器不会检查所有的Impossible WHERE的条件,因为这方面可能性太多了。例如:   CREATE TABLE Table1 (column1 CHAR(1)); ... SELECT * FROM Table1 WHERE column1 = 'Popgo'; 优化器不会剔除这种查询的条件,即使在CREATE TABLE定义中使之成为不可能的条件。       可合并的常数值    如下表达式会发生语句转化:   WHERE column1 = 1 + 2 最后为:   WHERE column1 = 3  在之前说的常数等值传递 ,优化器很容易将这种查询语句合并在一起。这操作就简化了结果。       常数值和常数表    MySQL常数值,有时不单单指在查询的SQL语句的字面意思上,也可在常数表(constant tables)的内容里。常数表(constant tables)被定义为:   1。无记录或一条记录的表   2。表的表达式被WHERE条件约束,而且包含的表达式形式column = "constant",或者表的主键的所有字段,或者任何唯一键的所有字段(唯一键的字段定义为NOT NULL)    例如,Table0表的定义包含:   ... PRIMARY KEY (column1,column2)  然后,查询表达式:   FROM Table0 ... WHERE column1=5 AND column2=7 ... 会返回常数表(constant tables)。更多简单地,如果Table1表的定义包含:   ... unique_not_null_column INT NOT NULL UNIQUE 然后,查询表达式:   FROM Table1 ... WHERE unique_not_null_column=5 也会返回常数表(constant tables)。        这个规则指一个常数表(constant tables)至多有一条记录值。MySQL就会优先评估是否为常数表(constant tables),并找出那个值。这样,MySQL会将这值插入查询语句。如这个例子:   SELECT Table1.unique_not_null_column, Table2.any_column     FROM Table1, Table2     WHERE Table1.unique_not_null_column = Table2.any_column     AND Table1.unique_not_null_column = 5; MySQL评估这语句时,首先就会发现,按照常数表(constant tables)的第二点定义,查询条件为unique_not_null_column的表Table1是一个常数表(constant tables),它就会取得这个值。   如果取值失败,也就是在表Table1里unique_not_null_column = 没值,EXPLAIN后结果:   Impossible WHERE noticed after reading const tables 相反,如果取值成功,也就是在表Table1里unique_not_null_column = 为一条记录值,MySQL会转化为如下语句:   SELECT 5, Table2.any_column     FROM Table1, Table2     WHERE 5 = Table2.any_column     AND 5 = 5;      事实上,这是一个很好的例子。优化器因前面提到的常数等值传递进行一些语句转化。另外,为什么要先描述常数等值传递,因为它在MySQL确认什么是常数表(constant tables)前就先进行了。优化器步骤的顺序,有时是有差别。    虽然很多查询都没常数表(constant tables)参考。应该牢记,以后无论什么时候,常数constant字被提及,它是指任何一个字面上的值或者一个常数表(constant tables)的内容。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表