데이터 베이스 MySQL 튜토리얼 从Mysql EXPLAIN探寻数据库查询优化_MySQL

从Mysql EXPLAIN探寻数据库查询优化_MySQL

Jun 01, 2016 pm 01:42 PM
어떻게 데이터베이스 쿼리

MySQLexplain

bitsCN.com
一. EXPLAIN 语法1. EXPLAIN tbl_name|SELECT select_options EXPLAIN tbl_name和DESCRIBE tbl_name的作用是一样的,用于显示表结构等信息。 当我们在select语句前加上EXPLAIN后,Mysql将告诉我们它是如何处理select语句的,提供表之间的联结方式、使用索引等有关信息。 二. 测试环境简单介绍为了节省创建表的时间,我用了joomla的文章表做测试,因为要演示优化过程,所以我事先删除了表里除主键之外的所有索引。这里用到了三个表:    mysql> explain jos_content;+------------------+------------------+------+-----+---------------------+----------------+| Field            | Type             | Null | Key | Default             | Extra          |+------------------+------------------+------+-----+---------------------+----------------+| id               | int(11) unsigned | NO   | PRI | NULL                | auto_increment || title            | varchar(255)     | NO   |     |                     |                || alias            | varchar(255)     | NO   |     |                     |                || title_alias      | varchar(255)     | NO   |     |                     |                || introtext        | mediumtext       | NO   |     | NULL                |                || fulltext         | mediumtext       | NO   |     | NULL                |                || state            | tinyint(3)       | NO   |     | 0                   |                || sectionid        | int(11) unsigned | NO   |     | 0                   |                || mask             | int(11) unsigned | NO   |     | 0                   |                || catid            | int(11) unsigned | NO   |     | 0                   |                || created          | datetime         | NO   |     | 0000-00-00 00:00:00 |                || created_by       | int(11) unsigned | NO   |     | 0                   |                || created_by_alias | varchar(255)     | NO   |     |                     |                || modified         | datetime         | NO   |     | 0000-00-00 00:00:00 |                || modified_by      | int(11) unsigned | NO   |     | 0                   |                || checked_out      | int(11) unsigned | NO   |     | 0                   |                || checked_out_time | datetime         | NO   |     | 0000-00-00 00:00:00 |                || publish_up       | datetime         | NO   |     | 0000-00-00 00:00:00 |                || publish_down     | datetime         | NO   |     | 0000-00-00 00:00:00 |                || images           | text             | NO   |     | NULL                |                || urls             | text             | NO   |     | NULL                |                || attribs          | text             | NO   |     | NULL                |                || version          | int(11) unsigned | NO   |     | 1                   |                || parentid         | int(11) unsigned | NO   |     | 0                   |                || ordering         | int(11)          | NO   |     | 0                   |                || metakey          | text             | NO   |     | NULL                |                || metadesc         | text             | NO   |     | NULL                |                || access           | int(11) unsigned | NO   |     | 0                   |                || hits             | int(11) unsigned | NO   |     | 0                   |                || metadata         | text             | NO   |     | NULL                |                |+------------------+------------------+------+-----+---------------------+----------------+30 rows in set (0.00 sec) mysql> select count(*) from jos_content;+----------+| count(*) |+----------+|    46585 |+----------+1 row in set (0.00 sec) mysql> desc jos_categories;+------------------+---------------------+------+-----+---------------------+----------------+| Field            | Type                | Null | Key | Default             | Extra          |+------------------+---------------------+------+-----+---------------------+----------------+    | id               | int(11)             | NO   | PRI | NULL                | auto_increment || parent_id        | int(11)             | NO   |     | 0                   |                || title            | varchar(255)        | NO   |     |                     |                || name             | varchar(255)        | NO   |     |                     |                || alias            | varchar(255)        | NO   |     |                     |                || image            | varchar(255)        | NO   |     |                     |                || section          | varchar(50)         | NO   |     |                     |                || image_position   | varchar(30)         | NO   |     |                     |                || description      | text                | NO   |     | NULL                |                || published        | tinyint(1)          | NO   |     | 0                   |                || checked_out      | int(11) unsigned    | NO   |     | 0                   |                || checked_out_time | datetime            | NO   |     | 0000-00-00 00:00:00 |                || editor           | varchar(50)         | YES  |     | NULL                |                || ordering         | int(11)             | NO   |     | 0                   |                || access           | tinyint(3) unsigned | NO   |     | 0                   |                || count            | int(11)             | NO   |     | 0                   |                || params           | text                | NO   |     | NULL                |                |+------------------+---------------------+------+-----+---------------------+----------------+17 rows in set (0.00 sec) mysql> select count(*) from jos_categories;+----------+| count(*) |+----------+|       18 |+----------+1 row in set (0.00 sec) mysql> desc jos_sections;+------------------+---------------------+------+-----+---------------------+----------------+| Field            | Type                | Null | Key | Default             | Extra          |+------------------+---------------------+------+-----+---------------------+----------------+    | id               | int(11)             | NO   | PRI | NULL                | auto_increment || title            | varchar(255)        | NO   |     |                     |                || name             | varchar(255)        | NO   |     |                     |                || alias            | varchar(255)        | NO   |     |                     |                || image            | text                | NO   |     | NULL                |                || scope            | varchar(50)         | NO   |     |                     |                || image_position   | varchar(30)         | NO   |     |                     |                || description      | text                | NO   |     | NULL                |                || published        | tinyint(1)          | NO   |     | 0                   |                || checked_out      | int(11) unsigned    | NO   |     | 0                   |                || checked_out_time | datetime            | NO   |     | 0000-00-00 00:00:00 |                || ordering         | int(11)             | NO   |     | 0                   |                || access           | tinyint(3) unsigned | NO   |     | 0                   |                || count            | int(11)             | NO   |     | 0                   |                || params           | text                | NO   |     | NULL                |                |+------------------+---------------------+------+-----+---------------------+----------------+15 rows in set (0.00 sec) mysql> select count(*) from jos_sections;+----------+| count(*) |+----------+|        2 |+----------+1 row in set (0.00 sec) 简单说明:jos_sections我们可以称它为大类表,jos_categories为小类表,jos_content为文章表,三个表的记录数分别为2、18、46585。 重要的字段基本上可以见名知义,只对几个联结字段说明一下:jos_categories.secion: 这个字段是jos_section的主键id,它表明了大类和小类的父子关系,至于jos_categories.parent_id,我们可以先无视它的存在。jos_content.sectionid: 这个字段也是jos_section的主键id,它表明了文章所属的大类。jos_content.catid: 这个字段是jos_categories的主键id,它表明了文章所属的小类。 至于为什么会用两个表来存储类别,而不用parent_id的方式实现无限级分类,我们也不必深究,因为这个就是joomla的结构,我们只是用来测试EXPLAIN而已。 三. 测试过程下面我们说明如何使用EXPLAIN查看执行过程并对表结构和sql语句进行优化。在下面的测试过程中,我会用一些看来根本就没有意义的SQL语句,只是为了演示SQL语句结构和输出效果,其可用价值我们大可不必过于追究,在实际生产中还要以实际应用为准。mysql> explain select * from jos_content where id=16;+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+| id | select_type | table       | type  | possible_keys | key     | key_len | ref   | rows | Extra |+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+|  1 | SIMPLE      | jos_content | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+    1 row in set (0.00 sec) 因为使用了EXPLAIN关键字,所以Mysql为我们列出了一些查询信息,它包含以下列: id: SELECT的识别符,这是SELECT的查询序列号。 select_type: SELECT类型,有以下几种不同的类型    (1).SIMPLE: 简单的SELECT(不使用UNION或子查询)    (2).PRIMARY: 最外面的SELECT,如果我们使用UNION或子查询,第一个查询将会是这个类型    (3).UNION: 使用UNION查询时,除第一个语句外的所有语句会返回这个类型    (4).DEPENDENT UNION: UNION中的第二个或后面的SELECT语句,取决于外面的查询。    (5).UNION RESULT: UNION的结果。    (6).SUBQUERY: 子查询中的第一个SELECT。    (7).DEPENDENT SUBQUERY: 子查询中的第一个SELECT,取决于外面的查询。    (8).DERIVED: 衍生表会返回这个类型。如:select * from (select * from jos_content) as A;。 table: 输出引用的表。 type: 联接类型,从这个选项我们可以初步判断查询效率,有以下几种不同的类型(按从最佳到最坏排序):    (1).system: 表中仅有一行记录,这是const的一个特例。    (2).const: 表中最多有一行符合查询条件,它在查询开始时被读取。因为只有一行,这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只被读取一次!(如上面的查询)    (3).eq_ref: 对于每个来自于前面的表的行组合,从该表中读取一行。例如:select * from A,B where A.id=B.id,如果id在B表中是unique或primary key,会返回这个类型。它是说对于A表中的每一行,在B表中读取符合记录的一行。除了const之外,这是最好的联接类型。    (4).ref: 这个类型跟eq_ref类似,不同的是eq_ref能根据unique或主键在后面的表中选择出唯一的行,而不能确定唯一行,则使用这个类型。    (5).ref_or_null: 该联接类型如同ref,但是添加了MySQL 可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。        (6).index_merge: 索引合并方法用于通过range扫描搜索行并将结果合成一个。合并会产生并集、交集或者正在进行的扫描的交集的并集。在EXPLAIN输出中,该方法表现 为type列内的index_merge。在这种情况下,key列包含一列使用的索引,key_len包含这些索引的最长的关键元素。    (7).unique_subquery: unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。explain select * from jos_content where id in (select id from jos_categories);会使用这个类型。    (8).index_subquery: 该联接类型类似于unique_subquery。可以替换IN子查询,但只适合子查询中的非唯一索引。    (9).range: 只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。 当使用=、、>、>=、、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用这个类型。    (10).index: 这与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。    (11).all: 对于每个来自于先前的表的行组合,将要做一个完整的表扫描。如果表格是第一个没标记const的表,效果不是很好,并且在所有的其他情况下很差。你可以通过增加更多的索引来避免ALL,使得行能从早先的表中基于常数值或列值被检索出来。    possible_keys: possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在 possible_keys中的某些键实际上不能按生成的表次序使用。如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询。 key: key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索 引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。对于MyISAM 和BDB 表,运行ANALYZE TABLE 可以帮助优化器选择更好的索引。对于MyISAM 表,可以使用myisamchk --analyze。 key_len: 此列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。在不损失精确性的情况下,长度越短越好。 ref: 此列显示使用哪个列或常数与key一起从表中选择行。 rows: 此列显示了MySQL认为它执行查询时必须检查的行数。 Extra: 该列包含MySQL解决查询的详细信息。        (1).Distinct: 一旦MYSQL找到了与行相联合匹配的行,就不再搜索了。    (2).Not exists: MYSQL 优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了。    (3).Range checked for each: Record(index map:#)没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。    (4).Using filesort: MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。    (5).Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候。    (6).Using temporary: 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上。    (7).Using where: 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题。    上面的解释,不必全部看懂,有些可以一带而过,因为确实有些抽象,有些我也只是摘抄,但是下面我们用几个具体的实例来更加深入地理解一下。mysql> explain select A.id,A.title,B.title from jos_content A,jos_categories B where A.catid=B.id;+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                 | rows  | Extra       |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+|  1 | SIMPLE      | A     | ALL    | NULL          | NULL    | NULL    | NULL                | 46585 |             ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid |     1 | Using where |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+2 rows in set (0.00 sec)  这个是我们经常使用的一种查询方式,对B表的联接类型使用了eq_ref,索引使用了PRIMARY,但是对于A表,却没有使用任何索引,这可能不是我们想要的。查看以上SQL语句,我们可能会想到,有必要给A.catid加个索引了。mysql> alter table jos_content add index idx_catid(`catid`);Query OK, 46585 rows affected (0.75 sec)    Records: 46585  Duplicates: 0  Warnings: 0 mysql> explain select A.id,A.title,B.title from jos_content A,jos_categories B where A.catid=B.id;+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                 | rows  | Extra       |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+|  1 | SIMPLE      | A     | ALL    | idx_catid     | NULL    | NULL    | NULL                | 46585 |             ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid |     1 | Using where |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+-------------+2 rows in set (0.00 sec)  这样表A便使用了idx_catid索引。 下面我们做一次三个表的联合查询mysql> explain select A.id,A.title,B.title from jos_content A,jos_categories B,jos_sections C where A.catid=B.id and A.sectionid=C.id;+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                 | rows  | Extra                          |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+|  1 | SIMPLE      | C     | index  | PRIMARY       | PRIMARY | 4       | NULL                |     2 | Using index                    ||  1 | SIMPLE      | A     | ALL    | idx_catid     | NULL    | NULL    | NULL                | 46585 | Using where; Using join buffer ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid |     1 | Using where                    |+----+-------------+-------+--------+---------------+---------+---------+---------------------+-------+--------------------------------+3 rows in set (0.00 sec)  这里显示了Mysql先将C表读入查询,并使用PRIMARY索引,然后联合A表进行查询,这时候type显示的是ALL,可以用的索引有idx_catid,但是实际没有用。    原因非常明显,因为使用的连接条件是A.sectionid=C.id,所以我们给A.sectionid加个索引先。mysql> alter table jos_content add index idx_section(`sectionid`);Query OK, 46585 rows affected (0.89 sec)Records: 46585  Duplicates: 0  Warnings: 0 mysql> explain select A.id,A.title,B.title from jos_content A,jos_categories B,jos_sections C where A.catid=B.id and A.sectionid=C.id;+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+| id | select_type | table | type   | possible_keys         | key         | key_len | ref                 | rows  | Extra       |+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+|  1 | SIMPLE      | C     | index  | PRIMARY               | PRIMARY     | 4       | NULL                |     2 | Using index ||  1 | SIMPLE      | A     | ref    | idx_catid,idx_section | idx_section | 4       | joomla_test.C.id    | 23293 | Using where ||  1 | SIMPLE      | B     | eq_ref | PRIMARY               | PRIMARY     | 4       | joomla_test.A.catid |     1 | Using where |+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+3 rows in set (0.00 sec) 这时候显示结果告诉我们,效果很明显,在连接A表时type变成了ref,索引使用了idx_section,如果我们注意看后两列,对A表的查询结果后一次明显少了一半左右,而且没有用到join buffer。这个表读入的顺序是Mysql优化器帮我们做的,可以得知,用记录数少的表做为基础表进行联合,将会得到更高的效率。 对于上面的语句,我们换一种写法mysql> explain select A.id,A.title,B.title from jos_content A left join jos_categories B on A.catid=B.id left join jos_sections C on A.sectionid=C.id;+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                     | rows  | Extra       |+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+|  1 | SIMPLE      | A     | ALL    | NULL          | NULL    | NULL    | NULL                    | 46585 |             ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid     |     1 |             ||  1 | SIMPLE      | C     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.sectionid |     1 | Using index |+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+-------------+    3 rows in set (0.00 sec)  Mysql 读入表的顺序被改变了,这意味着,如果我们用left join来做连接查询,Mysql会按SQL语句中表出现的顺序读入,还有一个有变化的地方是联接B和C的type都变成了eq_ref,前边我们说过, 这样说明Mysql可以找到唯一的行,这个效率是比ref要高的。 再来看一个排序的例子:mysql> explain select A.id,A.title,B.title from jos_content A left join jos_categories B on A.catid=B.id left join jos_sections C on A.sectionid=C.id order by B.id;+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                     | rows  | Extra                           |+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+|  1 | SIMPLE      | A     | ALL    | NULL          | NULL    | NULL    | NULL                    | 46585 | Using temporary; Using filesort ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid     |     1 |                                 ||  1 | SIMPLE      | C     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.sectionid |     1 | Using index                     |+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+3 rows in set (0.00 sec) mysql> explain select A.id,A.title,B.title from jos_content A left join jos_categories B on A.catid=B.id left join jos_sections C on A.sectionid=C.id order by A.id;+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+| id | select_type | table | type   | possible_keys | key     | key_len | ref                     | rows  | Extra          |    +----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+|  1 | SIMPLE      | A     | ALL    | NULL          | NULL    | NULL    | NULL                    | 46585 | Using filesort ||  1 | SIMPLE      | B     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.catid     |     1 |                ||  1 | SIMPLE      | C     | eq_ref | PRIMARY       | PRIMARY | 4       | joomla_test.A.sectionid |     1 | Using index    |+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+  对于上面两条语句,只是修改了一下排序字段,而第一个使用了Using temporary,而第二个却没有。在日常的网站维护中,如果有Using temporary出现,说明需要做一些优化措施了。而为什么第一个用了临时表,而第二个没有用呢?因为如果有ORDER BY子句和一个不同的GROUP BY子句,或者如果ORDER BY或GROUP BY中的字段都来自其他的表而非连接顺序中的第一个表的话,就会创建一个临时表了。那么,对于上面例子中的第一条语句,我们需要对jos_categories的id进行排序,可以将SQL做如下改动:mysql> explain select B.id,B.title,A.title from jos_categories A left join jos_content B on A.id=B.catid left join jos_sections C on B.sectionid=C.id order by A.id;+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+| id | select_type | table | type   | possible_keys | key       | key_len | ref                     | rows | Extra          |+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+|  1 | SIMPLE      | A     | ALL    | NULL          | NULL      | NULL    | NULL                    |   18 | Using filesort ||  1 | SIMPLE      | B     | ref    | idx_catid     | idx_catid | 4       | joomla_test.A.id        | 3328 |                ||  1 | SIMPLE      | C     | eq_ref | PRIMARY       | PRIMARY   | 4       | joomla_test.B.sectionid |    1 | Using index    |+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+3 rows in set (0.00 sec)  这样我们发现,不会再有Using temporary了,而且在查询jos_content时,查询的记录明显有了数量级的降低,这是因为jos_content的idx_catid起了作用。    所以结论是:尽量对第一个表的索引键进行排序,这样效率是高的。 我们还会发现,在排序的语句中都出现了Using filesort,字面意思可能会被理解为:使用文件进行排序或中文件中进行排序。实际上这是不正确的,这是一个让人产生误解的词语。当我们试图对一个没有索引的字段进行排序时,就是filesoft。它跟文件没有任何关系,实际上是内部的一个快速排序。 然而,当我们回过头来再看上面运行过的一个SQL的时候会有以下发现:mysql> explain select A.id,A.title,B.title from jos_content A,jos_categories B,jos_sections C where A.catid=B.id and A.sectionid=C.id order by C.id;+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+| id | select_type | table | type   | possible_keys         | key         | key_len | ref                 | rows  | Extra       |+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+|  1 | SIMPLE      | C     | index  | PRIMARY               | PRIMARY     | 4       | NULL                |     1 | Using index ||  1 | SIMPLE      | A     | ref    | idx_catid,idx_section | idx_section | 4       | joomla_test.C.id    | 23293 | Using where ||  1 | SIMPLE      | B     | eq_ref | PRIMARY               | PRIMARY     | 4       | joomla_test.A.catid |     1 | Using where |+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+3 rows in set (0.00 sec)  这是我们刚才运行过的一条语句,只是加了一个排序,而这条语句中C表的主键对排序起了作用,我们会发现Using filesort没有了。而尽管在上面的语句中也是对第一个表的主键进行排序,却没有得到想要的效果(第一个表的主键没有用到),这是为什么呢?实际上以上运行过的所有left join的语句中,第一个表的索引都没有用到,尽管对第一个表的主键进行了排序也无济于事。不免有些奇怪! 于是我们继续测试了下一条SQL:mysql> explain select A.id,A.title,B.title from jos_content A left join jos_categories B on A.catid=B.id left join jos_sections C on A.sectionid=C.id where A.id explain select A.id,A.title,B.title from jos_content A left join jos_categories B on A.catid=B.id left join jos_sections C on A.sectionid=C.id where A.id
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 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 옷 제거제

AI Hentai Generator

AI Hentai Generator

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

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

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

SublimeText3 중국어 버전

SublimeText3 중국어 버전

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

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

React Query에서 데이터베이스 쿼리에 대한 오류 처리 메커니즘 구현 React Query에서 데이터베이스 쿼리에 대한 오류 처리 메커니즘 구현 Sep 28, 2023 pm 02:40 PM

ReactQuery에서 데이터베이스 쿼리의 오류 처리 메커니즘 구현하기 ReactQuery는 데이터를 관리하고 캐싱하기 위한 라이브러리이며 프런트엔드 분야에서 점점 인기를 얻고 있습니다. 애플리케이션에서는 종종 데이터베이스와 상호 작용해야 하며 데이터베이스 쿼리로 인해 다양한 오류가 발생할 수 있습니다. 따라서 효과적인 오류 처리 메커니즘을 구현하는 것은 애플리케이션 안정성과 사용자 경험을 보장하는 데 중요합니다. 첫 번째 단계는 ReactQuery를 설치하는 것입니다. 다음 명령을 사용하여 프로젝트에 추가합니다.n

Java 개발 시 데이터베이스 쿼리 번호 오버플로 문제를 해결하는 방법 Java 개발 시 데이터베이스 쿼리 번호 오버플로 문제를 해결하는 방법 Jun 29, 2023 pm 06:46 PM

Java 개발 시 데이터베이스 쿼리 수 오버플로 문제 해결 방법 제목: Java 개발 시 데이터베이스 쿼리 수 오버플로 문제 해결 방법 요약: 인터넷의 발달과 데이터 양의 점진적인 증가로 인해 데이터베이스 쿼리도 증가하고 있습니다. Java 개발 시 메모리 제한으로 인해 데이터베이스 쿼리 수가 오버플로되는 문제가 발생할 수 있습니다. 이 기사에서는 이 문제를 해결하는 여러 가지 방법을 소개합니다. 텍스트: 데이터베이스 쿼리문 최적화 먼저, 데이터베이스 쿼리문 최적화 관점에서 이 문제를 해결할 수 있습니다. 우리는 사용할 수 있습니다

Laravel 미들웨어: 애플리케이션에 데이터베이스 쿼리 및 성능 모니터링을 추가하세요. Laravel 미들웨어: 애플리케이션에 데이터베이스 쿼리 및 성능 모니터링을 추가하세요. Jul 28, 2023 pm 02:53 PM

Laravel 미들웨어: 애플리케이션에 데이터베이스 쿼리 및 성능 모니터링 추가 소개: 웹 애플리케이션을 개발할 때 데이터 쿼리 및 성능 모니터링은 매우 중요합니다. Laravel은 이러한 요구 사항, 즉 미들웨어를 처리하는 편리한 방법을 제공합니다. 미들웨어는 요청과 응답 사이를 처리하는 기술로, 요청이 컨트롤러에 도달하기 전이나 응답이 사용자에게 반환된 후에 일부 논리를 수행할 수 있습니다. 이 글에서는 Laravel 미들웨어를 사용하여 데이터베이스 쿼리 및 성능 모니터링을 구현하는 방법을 소개합니다. 1. 중간 만들기

PHP를 사용하여 데이터베이스를 쿼리하고 결과를 표시하는 방법 PHP를 사용하여 데이터베이스를 쿼리하고 결과를 표시하는 방법 May 02, 2024 pm 02:15 PM

PHP를 사용하여 데이터베이스를 쿼리하고 결과를 표시하는 단계: 데이터베이스에 연결하여 결과를 표시하고 쿼리 결과의 행을 탐색하고 특정 열 데이터를 출력합니다.

PHP 데이터베이스 쿼리 팁: mysqli_query 함수를 사용하여 SQL 쿼리를 수행하는 방법 PHP 데이터베이스 쿼리 팁: mysqli_query 함수를 사용하여 SQL 쿼리를 수행하는 방법 Jul 29, 2023 pm 04:42 PM

PHP 데이터베이스 쿼리 팁: mysqli_query 함수를 사용하여 SQL 쿼리를 수행하는 방법 PHP 애플리케이션을 개발할 때 데이터베이스와의 상호 작용은 매우 중요한 부분입니다. 쿼리 작업을 위해 PHP는 SQL 문을 실행하는 몇 가지 내장 함수를 제공합니다. 이 기사에서는 개발자가 데이터베이스 쿼리 작업을 더 잘 수행할 수 있도록 mysqli_query 함수를 사용하는 방법에 중점을 둘 것입니다. 1. mysqli_query 함수 소개 mysqli_query 함수는 PHP에 내장된 함수입니다.

하얼빈 의과대학 임상약학 취업에 미래가 있나요? (하얼빈 의과대학 임상약학 취업 전망은 어떻습니까?) 하얼빈 의과대학 임상약학 취업에 미래가 있나요? (하얼빈 의과대학 임상약학 취업 전망은 어떻습니까?) Jan 02, 2024 pm 08:54 PM

하얼빈 의과대학 임상약학 취업 전망은 어떻습니까? 전국 취업 상황이 낙관적이지는 않지만 약학 졸업생의 취업 전망은 여전히 ​​좋습니다. 전반적으로 제약산업 졸업생의 공급은 수요보다 적다. 제약회사와 제약공장은 이러한 졸업생을 흡수하는 주요 통로이기도 하다. 보도에 따르면 최근 몇 년간 조제약품, 천연의약화학 등 전공 대학원생의 수급비율은 1:10에 달하기도 했다. 임상약학전공 취업방향: 임상의학을 전공하는 학생은 졸업 후 의료보건학과, 의학연구 및 기타 학과에서 진료, 예방, 의학연구 등에 종사할 수 있습니다. 채용 직위: 의료 담당자, 제약 영업 담당자, 영업 담당자, 영업 관리자, 지역 영업 관리자, 투자 관리자, 제품 관리자, 제품 전문가, 간호사

PHP 고성능: 데이터베이스 쿼리를 최적화하는 방법 PHP 고성능: 데이터베이스 쿼리를 최적화하는 방법 Jun 04, 2023 am 08:40 AM

오늘날 인터넷 시대에는 데이터의 폭발적인 증가와 함께 데이터베이스가 서비스의 핵심이 되었습니다. 데이터베이스의 성능과 속도는 웹 사이트와 해당 애플리케이션의 사용자 경험과 유용성에 직접적인 영향을 미칩니다. 따라서 데이터베이스 쿼리를 최적화하는 방법은 개발자가 집중해야 할 문제입니다. PHP 언어에서는 데이터베이스 쿼리문의 최적화를 통해 프로그램의 성능을 향상시키고, 서버의 부담을 줄이며, 서비스의 안정성을 향상시킬 수 있습니다. 이 기사에서는 다음 측면에서 데이터베이스 쿼리를 최적화하는 방법을 소개합니다. 1. 쿼리 수행 시 인덱스 사용

PHP에서 데이터베이스 쿼리 및 결과 매핑을 구현하는 방법은 무엇입니까? PHP에서 데이터베이스 쿼리 및 결과 매핑을 구현하는 방법은 무엇입니까? Jul 01, 2023 am 09:04 AM

PHP는 매우 유연하고 배우고 사용하기 쉬운 매우 인기 있는 서버측 프로그래밍 언어입니다. 데이터베이스 쿼리 및 결과 매핑은 웹 애플리케이션을 개발할 때 매우 중요한 단계입니다. 이 기사에서는 PHP가 데이터베이스 쿼리 및 결과 매핑을 구현하는 방법을 살펴보겠습니다. 먼저 데이터베이스 쿼리와 결과 매핑이 무엇인지 이해해 보겠습니다. 데이터베이스 쿼리는 데이터베이스 서버를 통해 데이터를 검색하는 프로세스입니다. 결과 매핑은 데이터베이스 쿼리 결과를 프로그램에서 사용할 수 있는 데이터 구조로 변환하는 프로세스입니다. PHP가 제공하는

See all articles