데이터 베이스 MySQL 튜토리얼 第7章:优化 (来自mysql手册)

第7章:优化 (来自mysql手册)

Jun 07, 2016 pm 03:26 PM
mysql 최적화 영향 수동 성명 첫 번째

首先,影响所有语句的一个因素是:你的许可设置得越复杂,所需要的开销越多。 执行 GRANT 语句时使用简单的许可,当客户执行语句时,可以使 MySQL 降低许可检查开销。例如,如果未授予任何表级或列级权限,服务器不需要检查 tables_priv 和 columns_priv 表

首先,影响所有语句的一个因素是:你的许可设置得越复杂,所需要的开销越多。

执行GRANT语句时使用简单的许可,当客户执行语句时,可以使MySQL降低许可检查开销。例如,如果未授予任何表级或列级权限,服务器不需要检查tables_privcolumns_priv表的内容。同样地,如果不对任何 账户进行限制,服务器不需要对资源进行统计。如果查询量很高,可以花一些时间使用简化的授权结构来降低许可检查开销。

如果你的问题是与具体MySQL表达式或函数有关,可以使用mysql客户程序所带的BENCHMARK()函数执行定时测试。其语法为BENCHMARK(loop_count,expression)。例如:

<span>mysql> </span><span><strong><span>SELECT BENCHMARK(1000000,1+1)</span><span>;</span></strong></span>
로그인 후 복사
<span>+------------------------+</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>| BENCHMARK(1000000,1+1) |</span>
로그인 후 복사
<span>+------------------------+</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>|                      0 |</span>
로그인 후 복사
<span>+------------------------+</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>1 row in set (0.32 sec)</span>
로그인 후 복사

上面结果在PentiumII 400MHz系统上获得。它显示MySQL在该系统上在0.32秒内可以执行1,000,000个简单的+表达式运算。

所有MySQL函数应该被高度优化,但是总有可能有一些例外。BENCHMARK()是一个找出是否查询有问题的优秀的工具。

7.2.1. EXPLAIN语法(获取SELECT相关信息)

<span>EXPLAIN </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사

或:

<span>EXPLAIN [EXTENDED] SELECT </span><span><em><span>select_options</span></em></span>
로그인 후 복사

EXPLAIN语句可以用作DESCRIBE的一个同义词,或获得关于MySQL如何执行SELECT语句的信息:

·         EXPLAIN tbl_nameDESCRIBE tbl_nameSHOW COLUMNS FROM tbl_name的一个同义词。

·         如果在SELECT语句前放上关键词EXPLAINMySQL将解释它如何处理SELECT,提供有关表如何联接和联接的次序。

该节解释EXPLAIN的第2个用法。

借助于EXPLAIN,可以知道什么时候必须为表加入索引以得到一个使用索引来寻找记录的更快的SELECT

如果由于使用不正确的索引出现了问题,应运行ANALYZE TABLE更新表的统计(例如关键字集的势),这样会影响优化器进行的选择。参见13.5.2.1节,“ANALYZE TABLE语法”。

还可以知道优化器是否以一个最佳次序联接表。为了强制优化器让一个SELECT语句按照表命名顺序的联接次序,语句应以STRAIGHT_JOIN而不只是SELECT开头。

EXPLAIN为用于SELECT语句中的每个表返回一行信息。表以它们在处理查询过程中将被MySQL读入的顺序被列出。MySQL用一遍扫描多次联接(single-sweep multi-join)的方式解决所有联接。这意味着MySQL从第一个表中读一行,然后找到在第二个表中的一个匹配行,然后在第3个表中等等。当所有的表处理完后,它输出选中的列并且返回表清单直到找到一个有更多的匹配行的表。从该表读入下一行并继续处理下一个表。

当使用EXTENDED关键字时,EXPLAIN产生附加信息,可以用SHOW WARNINGS浏览。该信息显示优化器限定SELECT语句中的表和列名,重写并且执行优化规则后SELECT语句是什么样子,并且还可能包括优化过程的其它注解。

EXPLAIN的每个输出行提供一个表的相关信息,并且每个行包括下面的列:

·         id

SELECT识别符。这是SELECT的查询序列号。

·         select_type

SELECT类型,可以为以下任何一种:

o        SIMPLE

简单SELECT(不使用UNION或子查询)

o        PRIMARY

最外面的SELECT

o        UNION

UNION中的第二个或后面的SELECT语句

o        DEPENDENT UNION

UNION中的第二个或后面的SELECT语句,取决于外面的查询

o        UNION RESULT

UNION的结果。

o        SUBQUERY

子查询中的第一个SELECT

o        DEPENDENT SUBQUERY

子查询中的第一个SELECT,取决于外面的查询

o        DERIVED

导出表的SELECT(FROM子句的子查询)

·         table

输出的行所引用的表。

·         type

联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序:

o        system

表仅有一行(=系统表)。这是const联接类型的一个特例。

o        const

表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次!

const用于用常数值比较PRIMARY KEYUNIQUE索引的所有部分时。在下面的查询中,tbl_name可以用于const表:

<span>SELECT * from </span><span><em><span>tbl_name</span></em></span><span> WHERE </span><span><em><span>primary_key</span></em></span><span>=1</span>;
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * from </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사
<span>WHERE </span><span><em><span>primary_key_part1</span></em></span><span>=1</span>和 <span><em><span>primary_key_part2</span></em></span><span>=2</span>;
로그인 후 복사

o        eq_ref

对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUEPRIMARY KEY

eq_ref可以用于使用=操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。

在下面的例子中,MySQL可以使用eq_ref联接来处理ref_tables

<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span><span>,</span><span><em><span>other_table</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>  WHERE </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column</span></em></span><span>=</span><span><em><span>other_table</span></em></span><span>.</span><span><em><span>column</span></em></span><span>;</span>
로그인 후 복사
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span><span>,</span><span><em><span>other_table</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>  WHERE </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column_part1</span></em></span><span>=</span><span><em><span>other_table</span></em></span><span>.</span><span><em><span>column</span></em></span>
로그인 후 복사
로그인 후 복사
<span>    AND </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column_part2</span></em></span><span>=1;</span>
로그인 후 복사
로그인 후 복사

o        ref

对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUEPRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。

ref可以用于使用=操作符的带索引的列。

在下面的例子中,MySQL可以使用ref联接来处理ref_tables

<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span><span> WHERE </span><span><em><span>key_column</span></em></span><span>=</span><span><em><span>expr</span></em></span><span>;</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span><span>,</span><span><em><span>other_table</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>  WHERE </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column</span></em></span><span>=</span><span><em><span>other_table</span></em></span><span>.</span><span><em><span>column</span></em></span><span>;</span>
로그인 후 복사
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span><span>,</span><span><em><span>other_table</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>  WHERE </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column_part1</span></em></span><span>=</span><span><em><span>other_table</span></em></span><span>.</span><span><em><span>column</span></em></span>
로그인 후 복사
로그인 후 복사
<span>    AND </span><span><em><span>ref_table</span></em></span><span>.</span><span><em><span>key_column_part2</span></em></span><span>=1;</span>
로그인 후 복사
로그인 후 복사

o        ref_or_null

该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。

在下面的例子中,MySQL可以使用ref_or_null联接来处理ref_tables

<span>SELECT * FROM </span><span><em><span>ref_table</span></em></span>
로그인 후 복사
<span>WHERE </span><span><em><span>key_column</span></em></span><span>=</span><span><em><span>expr</span></em></span><span> OR </span><span><em><span>key_column</span></em></span><span> IS NULL;</span>
로그인 후 복사

参见7.2.7节,“MySQL如何优化IS NULL”。

o        index_merge

该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。详细信息参见7.2.6节,“索引合并优化”。

o        unique_subquery

该类型替换了下面形式的IN子查询的ref

<span><em><span>value</span></em></span><span> IN (SELECT </span><span><em><span>primary_key</span></em></span><span> FROM </span><span><em><span>single_table</span></em></span><span> WHERE </span><span><em><span>some_expr</span></em></span><span>)</span>
로그인 후 복사

unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

o        index_subquery

该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:

<span><em><span>value</span></em></span><span> IN (SELECT </span><span><em><span>key_column</span></em></span><span> FROM </span><span><em><span>single_table</span></em></span><span> WHERE </span><span><em><span>some_expr</span></em></span><span>)</span>
로그인 후 복사

o        range

只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL

当使用=>>=IS NULLBETWEEN或者IN操作符,用常量比较关键字列时,可以使用range

<span>SELECT * FROM </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>WHERE </span><span><em><span>key_column</span></em></span><span> = 10;</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>WHERE </span><span><em><span>key_column</span></em></span><span> BETWEEN 10 and 20;</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>WHERE </span><span><em><span>key_column</span></em></span><span> IN (10,20,30);</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>SELECT * FROM </span><span><em><span>tbl_name</span></em></span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>WHERE </span><span><em><span>key_part1</span></em></span><span>= 10 AND </span><span><em>key_part2<span> IN (10,20,30);</span></em></span>
로그인 후 복사

o        index

该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。

当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。

o        ALL

对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。

·         possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。

如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询。参见13.1.2节,“ALTER TABLE语法”。

为了看清一张表有什么索引,使用SHOW INDEX FROM tbl_name

·         key

key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEXUSE INDEX或者IGNORE INDEX。参见13.2.7节,“SELECT语法”。

对于MyISAMBDB表,运行ANALYZE TABLE可以帮助优化器选择更好的索引。对于MyISAM表,可以使用myisamchk --analyze。参见13.5.2.1节,“ANALYZE TABLE语法”和5.9.4节,“表维护和崩溃恢复”。

·         key_len

key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。

·         ref

ref列显示使用哪个列或常数与key一起从表中选择行。

·         rows

rows列显示MySQL认为它执行查询时必须检查的行数。

·         Extra

该列包含MySQL解决查询的详细信息。下面解释了该列可以显示的不同的文本字符串:

o        Distinct

MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。

o        Not exists

MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。

下面是一个可以这样优化的查询类型的例子:

<span>SELECT * </span>从<span>t1 LEFT JOIN t2 ON t1.id=t2.id</span>
로그인 후 복사
<span>  WHERE t2.id IS NULL</span>;
로그인 후 복사

假定t2.id定义为NOT NULL。在这种情况下,MySQL使用t1.id的值扫描t1并查找t2中的行。如果MySQLt2中发现一个匹配的行,它知道t2.id绝不会为NULL,并且不再扫描t2内有相同的id值的行。换句话说,对于t1的每个行,MySQL只需要在t2中查找一次,无论t2内实际有多少匹配的行。

o        range checked for each record (index map: #)

MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用rangeindex_merge访问方法来索取行。关于适用性标准的描述参见7.2.5节,“范围优化”和7.2.6节,“索引合并优化”,不同的是前面表的所有列值已知并且认为是常量。

这并不很快,但比执行没有索引的联接要快得多。

o        Using filesort

MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。参见7.2.12节,“MySQL如何优化ORDER BY”。

o        Using index

从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一部分的列时,可以使用该策略。

o        Using temporary

为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BYORDER BY子句时。

o        Using where

WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALLindex,查询可能会有一些错误。

如果想要使查询尽可能快,应找出Using filesort Using temporaryExtra值。

o        Using sort_union(...), Using union(...), Using intersect(...)

这些函数说明如何为index_merge联接类型合并索引扫描。详细信息参见7.2.6节,“索引合并优化”。

o        Using index for group-by

类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BYDISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。详情参见7.2.13节,“MySQL如何优化GROUP BY”。

通过相乘EXPLAIN输出的rows列的所有值,你能得到一个关于一个联接如何的提示。这应该粗略地告诉你MySQL必须检查多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个乘积来确定执行哪个多表SELECT语句。参见7.5.2节,“调节服务器参数”。

下列例子显示出一个多表JOIN如何能使用EXPLAIN提供的信息逐步被优化。

假定你有下面所示的SELECT语句,计划使用EXPLAIN来检查它:

<span>EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,</span>
로그인 후 복사
<span>               tt.ProjectReference, tt.EstimatedShipDate,</span>
로그인 후 복사
<span>               tt.ActualShipDate, tt.ClientID,</span>
로그인 후 복사
<span>               tt.ServiceCodes, tt.RepetitiveID,</span>
로그인 후 복사
<span>               tt.CurrentProcess, tt.CurrentDPPerson,</span>
로그인 후 복사
<span>               tt.RecordVolume, tt.DPPrinted, et.COUNTRY,</span>
로그인 후 복사
<span>               et_1.COUNTRY, do.CUSTNAME</span>
로그인 후 복사
<span>        FROM tt, et, et AS et_1, do</span>
로그인 후 복사
<span>        WHERE tt.SubmitTime IS NULL</span>
로그인 후 복사
<span>          AND tt.ActualPC = et.EMPLOYID</span>
로그인 후 복사
<span>          AND tt.AssignedPC = et_1.EMPLOYID</span>
로그인 후 복사
<span>          AND tt.ClientID = do.CUSTNMBR;</span>
로그인 후 복사

对于这个例子,假定:

·         被比较的列声明如下:

列类型

tt

ActualPC

CHAR(10)

tt

AssignedPC

CHAR(10)

tt

ClientID

CHAR(10)

et

EMPLOYID

CHAR(15)

do

CUSTNMBR

CHAR(15)

·         表有下面的索引:

索引

tt

ActualPC

tt

AssignedPC

tt

ClientID

et

EMPLOYID(主键)

do

CUSTNMBR(主键)

·         tt.ActualPC值不是均匀分布的。

开始,在进行优化前,EXPLAIN语句产生下列信息:

<span> </span>

<span>table type possible_keys key  key_len ref  rows  Extra</span>
로그인 후 복사
<span>et    ALL  PRIMARY       NULL NULL    NULL 74</span>
로그인 후 복사
<span>do    ALL  PRIMARY       NULL NULL    NULL 2135</span>
로그인 후 복사
<span>et_1  ALL  PRIMARY       NULL NULL    NULL 74</span>
로그인 후 복사
<span>tt    ALL  AssignedPC,   NULL NULL    NULL 3872</span>
로그인 후 복사
<span>           ClientID,</span>
로그인 후 복사
<span>           ActualPC</span>
로그인 후 복사
<span>      range checked for each record (key map: 35)</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

因为type对每张表是ALL,这个输出显示MySQL正在对所有表产生一个笛卡尔乘积;即每一个行的组合!这将花相当长的时间,因为必须检查每张表的行数的乘积!对于一个实例,这是74 * 2135 * 74 * 3872 = 45,268,558,720行。如果表更大,你只能想象它将花多长时间……

这里的一个问题是MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引。在本文中,VARCHARCHAR是相同的,除非它们声明为不同的长度。因为tt.ActualPC被声明为CHAR(10)并且et.EMPLOYID被声明为CHAR(15),长度不匹配。

为了修正在列长度上的不同,使用ALTER TABLEActualPC的长度从10个字符变为15个字符:

<span>mysql> </span><span><strong><span>ALTER TABLE tt MODIFY ActualPC VARCHAR(15);</span></strong></span>
로그인 후 복사

现在tt.ActualPCet.EMPLOYID都是VARCHAR(15),再执行EXPLAIN语句产生这个结果:

<span> </span>

<span>table type   possible_keys key     key_len ref         rows    Extra</span>
로그인 후 복사
<span>tt    ALL    AssignedPC,   NULL    NULL    NULL        3872    Using</span>
로그인 후 복사
<span>             ClientID,                                         where</span>
로그인 후 복사
로그인 후 복사
<span>             ActualPC</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>do    ALL    PRIMARY       NULL    NULL    NULL        2135</span>
로그인 후 복사
<span>      range checked for each record (key map: 1)</span>
로그인 후 복사
로그인 후 복사
<span>et_1  ALL    PRIMARY       NULL    NULL    NULL        74</span>
로그인 후 복사
<span>      range checked for each record (key map: 1)</span>
로그인 후 복사
로그인 후 복사
<span>et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC 1</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

这不是完美的,但是好一些了:rows值的乘积少了一个因子74。这个版本在几秒内执行完。

2种方法能消除tt.AssignedPC = et_1.EMPLOYIDtt.ClientID = do.CUSTNMBR比较的列的长度失配问题:

<span>mysql> </span><span><strong><span>ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),</span></strong></span>
로그인 후 복사
<span>    ->                </span><span><strong><span>MODIFY ClientID   VARCHAR(15);</span></strong></span>
로그인 후 복사

EXPLAIN产生的输出显示在下面:

<span>table type   possible_keys key      key_len ref           rows Extra</span>
로그인 후 복사
<span>et    ALL    PRIMARY       NULL     NULL    NULL          74</span>
로그인 후 복사
<span>tt    ref    AssignedPC,   ActualPC 15      et.EMPLOYID   52   Using</span>
로그인 후 복사
<span>             ClientID,                                         where</span>
로그인 후 복사
로그인 후 복사
<span>             ActualPC</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>et_1  eq_ref PRIMARY       PRIMARY  15      tt.AssignedPC 1</span>
로그인 후 복사
<span>do    eq_ref PRIMARY       PRIMARY  15      tt.ClientID   1</span>
로그인 후 복사
<span> </span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

这几乎很好了。

剩下的问题是,默认情况,MySQL假设在tt.ActualPC列的值是均匀分布的,并且对tt表不是这样。幸好,很容易告诉MySQL来分析关键字分布:

<span>mysql> </span><span><strong><span>ANALYZE TABLE tt</span><span>;</span></strong></span>
로그인 후 복사

现在联接是“完美”的了,而且EXPLAIN产生这个结果:

<span>table type   possible_keys key     key_len ref           rows Extra</span>
로그인 후 복사
<span>tt    ALL    AssignedPC    NULL    NULL    NULL          3872 Using</span>
로그인 후 복사
<span>             ClientID,                                        where</span>
로그인 후 복사
<span>             ActualPC</span>
로그인 후 복사
로그인 후 복사
로그인 후 복사
<span>et    eq_ref PRIMARY       PRIMARY 15      tt.ActualPC   1</span>
로그인 후 복사
<span>et_1  eq_ref PRIMARY       PRIMARY 15      tt.AssignedPC 1</span>
로그인 후 복사
<span>do    eq_ref PRIMARY       PRIMARY 15      tt.ClientID   1</span>
로그인 후 복사

注意在从EXPLAIN输出的rows列是一个来自MySQL联接优化器的“教育猜测”。你应该检查数字是否接近事实。如果不是,可以通过在SELECT语句里面使用STRAIGHT_JOIN并且试着在FROM子句以不同的次序列出表,可能得到更好的性能。

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 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 옷 제거제

Video Face Swap

Video Face Swap

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

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

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

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

MySQL : 세계에서 가장 인기있는 데이터베이스 소개 MySQL : 세계에서 가장 인기있는 데이터베이스 소개 Apr 12, 2025 am 12:18 AM

MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템으로, 주로 데이터를 신속하고 안정적으로 저장하고 검색하는 데 사용됩니다. 작업 원칙에는 클라이언트 요청, 쿼리 해상도, 쿼리 실행 및 반환 결과가 포함됩니다. 사용의 예로는 테이블 작성, 데이터 삽입 및 쿼리 및 조인 작업과 같은 고급 기능이 포함됩니다. 일반적인 오류에는 SQL 구문, 데이터 유형 및 권한이 포함되며 최적화 제안에는 인덱스 사용, 최적화 된 쿼리 및 테이블 분할이 포함됩니다.

phpmyadmin을 여는 방법 phpmyadmin을 여는 방법 Apr 10, 2025 pm 10:51 PM

다음 단계를 통해 phpmyadmin을 열 수 있습니다. 1. 웹 사이트 제어판에 로그인; 2. phpmyadmin 아이콘을 찾고 클릭하십시오. 3. MySQL 자격 증명을 입력하십시오. 4. "로그인"을 클릭하십시오.

MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점 MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점 Apr 12, 2025 am 12:17 AM

MySQL은 성능, 신뢰성, 사용 편의성 및 커뮤니티 지원을 위해 선택됩니다. 1.MYSQL은 효율적인 데이터 저장 및 검색 기능을 제공하여 여러 데이터 유형 및 고급 쿼리 작업을 지원합니다. 2. 고객-서버 아키텍처 및 다중 스토리지 엔진을 채택하여 트랜잭션 및 쿼리 최적화를 지원합니다. 3. 사용하기 쉽고 다양한 운영 체제 및 프로그래밍 언어를 지원합니다. 4. 강력한 지역 사회 지원을 받고 풍부한 자원과 솔루션을 제공합니다.

MySQL의 장소 : 데이터베이스 및 프로그래밍 MySQL의 장소 : 데이터베이스 및 프로그래밍 Apr 13, 2025 am 12:18 AM

데이터베이스 및 프로그래밍에서 MySQL의 위치는 매우 중요합니다. 다양한 응용 프로그램 시나리오에서 널리 사용되는 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1) MySQL은 웹, 모바일 및 엔터프라이즈 레벨 시스템을 지원하는 효율적인 데이터 저장, 조직 및 검색 기능을 제공합니다. 2) 클라이언트 서버 아키텍처를 사용하고 여러 스토리지 엔진 및 인덱스 최적화를 지원합니다. 3) 기본 사용에는 테이블 작성 및 데이터 삽입이 포함되며 고급 사용에는 다중 테이블 조인 및 복잡한 쿼리가 포함됩니다. 4) SQL 구문 오류 및 성능 문제와 같은 자주 묻는 질문은 설명 명령 및 느린 쿼리 로그를 통해 디버깅 할 수 있습니다. 5) 성능 최적화 방법에는 인덱스의 합리적인 사용, 최적화 된 쿼리 및 캐시 사용이 포함됩니다. 모범 사례에는 거래 사용 및 준비된 체계가 포함됩니다

Apache의 데이터베이스에 연결하는 방법 Apache의 데이터베이스에 연결하는 방법 Apr 13, 2025 pm 01:03 PM

Apache는 데이터베이스에 연결하여 다음 단계가 필요합니다. 데이터베이스 드라이버 설치. 연결 풀을 만들려면 Web.xml 파일을 구성하십시오. JDBC 데이터 소스를 작성하고 연결 설정을 지정하십시오. JDBC API를 사용하여 Connections, 명세서 작성, 매개 변수 바인딩, 쿼리 또는 업데이트 실행 및 처리를 포함하여 Java 코드의 데이터베이스에 액세스하십시오.

Docker의 MySQL을 시작하는 방법 Docker의 MySQL을 시작하는 방법 Apr 15, 2025 pm 12:09 PM

Docker에서 MySQL을 시작하는 프로세스는 다음 단계로 구성됩니다. MySQL 이미지를 가져와 컨테이너를 작성하고 시작하고 루트 사용자 암호를 설정하고 포트 확인 연결을 매핑하고 데이터베이스를 작성하고 사용자는 데이터베이스에 모든 권한을 부여합니다.

MySQL의 역할 : 웹 응용 프로그램의 데이터베이스 MySQL의 역할 : 웹 응용 프로그램의 데이터베이스 Apr 17, 2025 am 12:23 AM

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

CentOS7에 MySQL을 설치하는 방법 7 CentOS7에 MySQL을 설치하는 방법 7 Apr 14, 2025 pm 08:30 PM

MySQL을 우아하게 설치하는 열쇠는 공식 MySQL 저장소를 추가하는 것입니다. 특정 단계는 다음과 같습니다. 피싱 공격을 방지하기 위해 MySQL 공식 GPG 키를 다운로드하십시오. MySQL 리포지토리 파일 추가 : rpm -uvh https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm yum repository cache : yum 업데이트 설치 mysql : yum 설치 mysql-server startup startup mysql 서비스 : systemctl start mysqlctl start mysqlctl.

See all articles