SQL 如何两次LIKE内关联查询?

本文已收录到1.1K Star数开源学习指南——《大厂面试指北》,如果想要了解更多大厂面试相关的内容及获取《大厂面试指北》离线PDF版,请扫描下方二维码码关注公众号“大厂面试”,谢谢大家了!

《大厂面试指北》最佳阅读地址:

《大厂面试指北》项目地址:

获取《大厂面试指北》离线PDF版,请扫描下方二维码关注公众号“大厂面试”

《大厂面试指北》项目截图:

因为我最近的一些工作内容跟数据分析比较密切,所以需要对SQL使用得比较熟练,所以便阅读了《MySQL 必知必会》这本书,为了检验自己的阅读效果及帮助一些跟我一样需要学习MySQL相关的知识的朋友,所以每阅读一章,我就开始写一章的读书笔记,并在掘金的读书笔记版块发布沸点。一共三十章,全部发布完以后,便汇总成了这篇文章,感兴趣的朋友通过阅读这篇文章,快速得预览这本书,学习MySQL相关的知识。如果你觉得这本书对你带来帮助,希望你可以为我点一个关注,后续也会继续阅读其他的技术书籍,并整理成读书笔记,分享给大家。同时也欢迎大家加我的微信,我们一起探讨学习。

本章主要是介绍了一些数据库相关的概念:

数据库:保存有组织的数据的容器。

表:某种特定类型数据的结构化清单。

模式(schema):关于数据库和表的布局及特性的信息。在MYSQL中,模式与数据库同义。

主键:唯一标识表中每行的这个列称为主键。一个列成为主键必须满足以下条件:

1.唯一性,任意两行都不具有相同的主键值。

2.不为空,每行数据必须具有一个主键值。

DBMS(数据库管理软件)通常分为两类:

2.Client-Sever的DBMS。日常见到的MySQL,Oracle,SQL Server数据库都是这种类型的。Client主要负责与用户进行交互,接受用户的指令,然后发出请求给Server,Server负责数据访问和处理,然后将结果返回给Client。

主要介绍了一些MySQL的一些命令

use crashcourse;选择一个名叫crashcourse数据库(在通过命令行连接到数据库时,我们需要选择一个数据库,然后才能继续操作)

show Tables;//展示当前是选择的是数据库的所有表

展示之前创建crashcourse这个数据库时使用的SQL语句,同理,SHOW CREATE TABLE也可以展示建某张表时使用的SQL语句

HELP SHOW;当你不了解某个命令时,可以使用HELP+这个命令,来获得一些说明信息,了解这个命令的用途,这里HELP SHOW会打印出SHOW命令的用法

这两章主要讲得是查询相关的。

查询时默认的数据顺序:

如果是不设置任何排序条件,以这种方式来进行查询,返回的数据的顺序是根据它们在底层表中出现的顺序(可以是数据最初添加到表中的顺序,但是如果数据进行过更新或删除,顺序会受到MySQL重用回收存储空间的影响)

如果想要对让返回的数据不包含重复值,可以使用DISTINCT来对列进行修饰

DISTINCT关键字是对所有字段进行修饰的,只有当所有列都相同时,才会进行排除,在上面这个例子中,只有vend_id和prod_price都相同的数据,才会进行排除,也就是可以允许一些vend_id相同,prod_price不同的数据出现。

使用LIMIT来限制结果

可以限制返回的数据为5条

可以限制返回的数据是从第4行开始后面的5条

上面这条查询语句,MySQL 5以后还支持另外一种更加容易理解的写法

可以限制在某个数据库的某个表中进行查询,上面的例子是限制了,必须在crash_course数据库的products表取prod_name列的数据

这一章主要讲的是ORDER BY对查询结果进行排序,以及使用ASC,DESC控制升序,降序。

在 ORDER BY 指定多个字段,可以按规定的顺序,按多个列排序,例子中的数据会先根据 product_price 从低到高进行排序,如果 product_price相同,再按 product_name ,就进行比较从A到Z进行排序,如下图所示

默认的排序方向是升序,也就是ASC,有时候需要进行降序排序,例如价格从高到低进行排序,可以使用降序DESC

这一章其实主要讲得是WHERE语句对数据进行过滤。

一些常见的WHERE语句的条件判断符,大家已经知道了。

除了上面这些,有一个不太常见的操作符号

!= 是返回不具备特定值的行,NULL值代表未知,所以不会拿NULL值去跟特定值比较,所以不会具有NULL值的行。如果想要获取具有NULL值的行,必须使用IS NULL

只会返回value为200的这一行,不会返回值为NULL的行

使用BETWEEN操作符会匹配范围中所有的值,包括指定的开始值和结束值

这一章主要说的是AND,OR, IN,NOT这四个操作符,

组合AND和OR使用时,因为AND优先级最高计算时会优先处理AND操作符,会将AND两边的条件进行提取,所以上面这个SQL语句其实会等价于

可能会与我们想要的结果会有一定差距,我们是想要

可能会与我们想要的结果会有一定差距,我们是想要vend_id为1002或1002,且prod_price大于10的数据,所以在日常使用中,最好使用()明确地分组相应的操作符,而不是依赖操作符的优先级,像下面这样:

在指定条件范围进行匹配时,IN和OR都能满足需求,但是IN有一些优点:

1.IN操作符语法更加简洁直观,容易管理

2.IN操作符执行更快。

3.IN的最大优点是可以包含其他SELECT语句,从而可以动态地简历WHERE语句,第14章会对此进行详细介绍。

其他DBMS允许使用NOT对各种条件取反,但在MySQL中,只支持使用NOT对IN、BETWEEN和EXISTS子句取反。

第八章 用通配符进行过滤

这一章主要是介绍了LIKE操作符,以及%,_ 这两个通配符。

LIKE主要是配合通配符一起使用的,LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式。

%代表搜索模式中给定位置的0个、1个或多个字符。

在一个查询语句中也可以使用多个%通配符

可能会干扰通配符匹配。例如,在保存词 anvil时,如果它后面有一个或多个空格,则子句WHERE prod_name LIKE '%anvil'将不会匹配它们,因为在最后的l 后有多余的字符。解决这个问题的一个简单的办法是在搜索模式最后附加一个%。一个更好的办法是使用函数(第11章将会 介绍)去掉首尾空格。
虽然似乎%通配符可以匹配任何东西,但有一个例 外,即NULL。即使是WHERE prod_name LIKE '%'也不能匹配 用值NULL作为产品名的行。
_通配符与%通配符类似,只不过只能匹配单个字符,不能匹配0个字符,也不能匹配多个字符

1.在能使用其他操作符的请款下,尽量不要使用通配符,因为它的搜索事件要比其他操作符的长

2.尽量不要把通配符用在搜索模式的开始处。放在搜索模式的开始处,搜索起来是最慢的。

3.仔细检查通配符的位置。如果放错地方,可能不会返回想要的数据。

第九章 用正则表达式进行搜索

这一章主要讲得是正则相关的知识,我个人认为把正则当成一门单独的技术进行学习会比较好,所以建议可以专门去学习

某些场景下,存储在的表中的数据不是我们所需要的,我们需要对它进行转换、计算或格式化过,这就是计算字段的用途。

使用Concat()函数对字段进行拼接

多数DBMS使用+或||来实现拼接, MySQL则使用Concat()函数来对字段进行拼接。Concat()可以将多个字符串拼接成一个,如下图所示:

使用Trim()函数来去除空格

Trim()函数 :去除字符串左右两边的空格
LTrim()函数 :去除字符串左边的空格
RTrim()函数 :去除字符串右边的空格
下面是使用RTrim()函数的例子

我们使用Concat()函数拼接出来的字段是没有名字的,可以使用AS关键字给它赋予一个名字,当然当已有的字段包含不符合规定的字符时,也可以AS关键字给一个已有字段起别名。

除了使用Concat()函数得到一个计算字符,也可以使用+,-,*,/计算得到一个字段。如图所示:

第十一章 使用数据处理函数

除了使用SQL语句对数据进行处理,还可以使用一些函数对数据进行处理,需要注意的是,函数没有SQL的可移植性那么强。

这是使用Upper()函数将文本处理成大写的案例

上面这些常见函数大家可能都能够理解,只有Soundex()不太常见,SOUNDEX是一个将任何文 本串转换为描述其语音表示的字母数字模式的算法。

如上图所示,假设有一个顾客的cust_contact值为Y.Lee,但是我们不知道Y.Lee,只知道这个顾客的名字的发音近似于Y.Lie,这个时候我们可以使用Soundex()将cust_contact列值转换为它的SOUNDEX值,因为Y.Lee和 Y.Lie发音相似,所以它们的SOUNDEX值匹配,因此可以查询到这个顾客。

常用日期和时间处理函数


举例,使用Date函数提取日期部分:

在日常开发中,我们除了获得检索得到的数据,还可以使用聚合函数对数据汇总,得到处理后的结果。

AVG()是计算特定列的平均值,会忽略掉值为NULL的列。

AVG()函数也可以搭配DISTINCT关键字使用,将重复的数据去重后,然后计算平均值,如下图所示:

在使用了DISTINCT后,此例子中的avg_price比较高,因为有多个物品具有相同的较低价格。排除它们提升了平均价格。

1.使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
2.使用COUNT(column)对特定列中具有值的行进行计数,会忽略 NULL值。

这一章主要讲了如果使用GROUP BY 对数据进行分组。

如果要对分组进行过滤,我们可以使用WHERE语句对表中数据进行过滤后,然后使用GROUP BY进行分组,也可以在使用GROUP BY进行分组后,再使用HAVING语句过滤掉一些分组。

对于上面这个表的数据,如果我们想要过滤掉id为3的分组,那么可以写成使用WHERE语句的方式:

也可以写成使用HAVING语句的方式:

当然在过滤分组这方面,HAVING要比WHERE更加强大,比如我们想要对数据分组,并且得到数量大于2的组,那么WHERE就无法实现,只能用HAVING语句。如下:

使用GROUP BY在对数据进行分组后,输出的组的顺序通常是按从小到到大,从A到Z升序输出的,但是SQL规范并没有对此进行明确要求,所以有可能不是顺序的,可以使用ORDER BY来对分组进行升序或者降序排序。

在使用这些语句时,它们的先后顺序应该要按下面的表中顺序来写

子查询作为WHERE子句的条件

有时候一条SELECT语句无法满足我们的需求,我们可以把一条SELECT语句的结果用于另外一条SELECT语句的WHERE子句,来实现复杂查询。

例如:我们想要获取订购物品TNT2的所有客户的名字和联系方式:
可以按照下图中的复杂查询实现:

(1) 查询包含物品TNT2的所有订单的编号。
(2) 根据订单编号查询所有客户的ID。
(3) 根据客户的ID查询名字和联系方式。

在WHERE子句中使用子查询能够编写出功能很强并且很灵活的 SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于 性能的限制,不能嵌套太多的子查询。

1.能嵌套的子查询的数目没有限制,不过在实际使用时由于 性能的限制,不能嵌套太多的子查询。

2.列必须匹配,在WHERE子句中使用子查询,应该保证SELECT语句具有与WHERE子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。

3.子查询一般与IN操作符结合使用,但也可以用于测试等于(=)、 不等于(<>)等。

子查询结果作为计算字段

例如:我们想要在获取顾客的信息的同时,获取客户的订单数,可以使用子查询来实现,如下图所示:

当然这个需求也可以使用JOIN来实现

有时候针对单表的查询无法满足我们的需求,我们需要连接多个表,返回一组输出。连接并不是物理实体,只是在查询时建立。

在进行连接查询时,如果不指定任何WHERE 条件,那么返回的结果会是笛卡尔积,会拿第一个表中的行数与第二个表中的所有行进行配对,最终总行数会是第一个表的行数乘以第二个表中的行数。

如果指定了WHERE条件,得到的结果会是根据条件对笛卡尔积的结果进行筛选过滤后的结果。例如在这个例子中,指定了products表的vend_id与vendors表的vend_id相等作为筛选条件,这样,连接的结果就是拿vendors表的vend_id去products表中找相匹配的数据。

上面的这种连接其实是等值连接,可以用连接的语法来写,可以更加明确连接类型

一条SELECT语句可以连接的表的数量没有限制,可以连接多个表,进行查询

之前通过子查询嵌套来完成多表查询,现在可以使用连接来实现

第十六章 创建高级联结

本章将讲解外连接,以及如何对被联结的表使用表别名和聚集函数。

除了可以对列,计算字段起别名以外,还可以对表起别名。主要有以下好处:

1.缩短SQL语句(有些表名太长,可以起短的别名)

2.允许在单条SELECT语句中多次使用相同的表(对表进行自连接查询时会需要多次使用相同的表,在下面有相应的例子说明)

除了上一章讲到的内部连接(等值连接)以为,还有自连接,自然连接,外部连接三种连接:

自连接指的是一张表对自身进行连接,进行信息查询。
某物品(其ID为DTNTR)存在问题,因此想知道生产该物 品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到 生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。
可以使用自连接的实现:

此查询中需要的两个表实际上是相同的表,因此products表在
FROM子句中出现了两次。虽然这是完全合法的,但对products 的引用具有二义性,所以使用表别名避免歧义。
当然解决上面的这个查询需求也可以使用子查询来实现,如下图所示:

内部连接会将一个表中的行与另一个表中的行想关联,有时候也需要包含不满足关联条件的那些行,这就是外连接。

这条SELECT语句使用了关键字OUTER JOIN来指定联结的类型(而不是在WHERE子句中指 定)。但是,与内部联结关联两个表中的行不同的是,外部联结还包括没 有关联行的行。在使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字 指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT 指出的是OUTER

聚集函数也可以和连接结合起来使用。

1.注意所使用的联结类型。一般我们使用内部联结,但使用外部联 结也是有效的。

2.保证使用正确的联结条件,否则将返回不正确的数据。

3.应该总是提供联结条件,否则会得出笛卡儿积。

4.在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前,分别测试每个联结。这将使故障排除更为简单。

在 MySQL 中,可以执行多条查询语句,然后对多个结果集,使用UNION语句合并成单个查询结果集返回。主要有以下两种应用场景:
1.在单个查询中从不同的表返回类似结构的数据。
2.对单个表执行多个查询,将结果集合并成一个结果集。

例如我们需要价格小于等于5的所有物品的一个列表,而且 还想包括供应商1001和1002生产的所有物品(不考虑价格),

这条语句由前面的两条SELECT语句组成,语句中用UNION关键
字分隔。UNION指示MySQL执行两条SELECT语句,并把输出组 合成单个查询结果集,当然这个需求也可以使用多条WHERE语句来实现。

1.UNION必须由两条或两条以上的SELECT语句组成,语句之间用关 键字UNION分隔(因此,如果组合4条SELECT语句,将要使用3个 UNION关键字)。

2.UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过
3.列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以
隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。 如果遵守了这些基本规则或限制,则可以将并用于任何数据检索任务。

4.在用UNION组合查询时,如果需要对结果进行排序,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对 于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一 部分的情况,因此不允许使用多条ORDER BY子句。

5.UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与 单条SELECT语句中使用多个WHERE子句条件一样)。因为供应商1002生产 的一种物品的价格也低于5,所以两条SELECT语句都返回该行。在使用 UNION时,重复的行被自动取消。这是UNION的默认行为,但是如果允许重复,可以使用UNION ALL而不是UNION。如下图所示:

当我们需要对文本进行匹配,可以使用LIKE+通配符,或正则表达式的方式来实现,但是这样会存在很多限制:

1.性能不高——通配符和正则表达式匹配通常要求MySQL尝试匹配表中所有行(而且这些搜索极少使用表索引)。因此,由于被搜索行数不断增加,这些搜索可能非常耗时。

2.不太灵活——使用通配符和正则表达式匹配,很难(而且并不总是能)明确地控制匹配什么和不匹配什么。例如,指定一个词必须匹配,一个词必须不匹配,而一个词仅在第一个词确实匹配的情况下才可以匹配或者才可以不匹配。

3.无法智能化——虽然基于通配符和正则表达式的搜索提供了非常灵活的搜索,但它们都不能提供一种智能化的选择结果的方法。 例如,一个特殊词的搜索将会返回包含该词的所有行,而不区分包含单个匹配的行和包含多个匹配的行(按照可能是更好的匹配 来排列它们)。类似,一个特殊词的搜索将不会找出不包含该词但包含其他相关词的行。所以就有了全文搜索,为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改 变不断地重新索引。在对表列进行适当设计后,MySQL会自动进行所有 的索引和重新索引。在索引之后,SELECT可与Match()和Against()一起使用以实际执行 搜索。

在建表时或者建表以后使用FULLTEXT语句指定全文搜索的列,MySQL根据子句FULLTEXT(note_text)的指示对它进行索引,在之后该列增加、更新或删除行时, 索引随之自动更新

如果正在导入数据到一个新表, 此时不应该启用FULLTEXT索引。应该首先导入所有数据,然后再修改表,定义FULLTEXT,这样花费的时间会更少。

在索引之后,使用两个函数Match()和Against()执行全文本搜索,
Against() 指定要使用的搜索表达式
如下图所示:SELECT语句检索单个列note_text,将包含rabbit的行进行返回。(全文搜索默认不区分大小写,除非使用BINARY语句进行修饰)

全文搜索还可以使用Rank对结果进行排序,Match()和Against() 用来建立一个计算列(别名为rank),此列包含全文本搜索计算出的等级 值。等级由MySQL根据行中词的数目、唯一词的数目、整个索引中词的 总数以及包含该词的行的数目计算出来。不包含搜索词的行等级为0(因此不被前一例子中的WHERE子句选择)。确实包含搜索词的两个行每行都有一个等级值,文本中词靠前的行的等级值比词靠后的行的等级值高。如下图所示:

如果指定多个搜索项,则包含多数匹配词的 那些行将具有比包含较少词(或仅有一个匹配)的那些行高的 等级值。

查询扩展用来设法放宽所返回的全文本搜索结果的范围,它可以先进行一个基本的全文本搜索,找出与搜索条件匹配的所有行。其次,MySQL检查这些匹配行并选择所有有用的词,再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件, 而且还使用所有有用的词。如下图所示;

MySQL支持全文本搜索的另外一种形式,称为布尔方式(boolean
mode)。可以指定要匹配的词,要排斥的词,排列提示(指定某些词比其他词更重要,更重要的词等级更高),表达式分组等。即使没有定义 FULLTEXT索引,也可以使用它。但这是一种非常缓慢的操作。
在下图里面的查询中,会匹配词heavy,但-rope*明确地

除了布尔操作符-和,-排除一个词,而 是截断操作符(可想象为用于词尾的一个通配符)。还有以下全文本布尔操作符:

下面是一些全文本布尔操作符使用案例:

1.在索引全文本数据时,短词被忽略且从索引中排除。短词定义为 那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。

2.MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表(请参阅MySQL文档以了解如何完成此工作)。

3.许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。因此,MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE。

4.如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词或者不出现,或者至少出现在50%的行中)。

5.忽略词中的单引号。例如,don't索引为dont。

6.不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文

7.如前所述,仅在MyISAM数据库引擎中支持全文本搜索。

8.没有邻近操作符,邻近搜索是许多全文本搜索支持的一个特 性,它能搜索相邻的词(在相同的句子中、相同的段落中或者 在特定数目的词的部分中,等等。MySQL全文本搜索现在还不支持邻近操作符。

使用INSERT语句插入数据,大家都很熟悉。

一般推荐第二张方式,因为第一种方式的数据顺序必须与列在表中的数据保持一致,容易写错,其次是当表结构发生改变时,第一种方式需要变更数据顺序,第二种方式不需要。

INSERT一般用来给表插入一个指定列值的行。但是,INSERT还存在 另一种形式,可以利用它将一条SELECT语句的结果插入表中。如下图所示,这个例子使用INSERT SELECT从custnew表中将所有数据导入customers表

第二十章 更新和删除数据

使用UPDATE语句更新数据,大家都很熟练了,一般UPDATE语句组成部分如下:


1.在使用UPDATE语句时,不要省略WHERE子句 ,否则就会更新表中所有行。

2.IGNORE关键字,如果用UPDATE语句更新多行,并且在更新这些行中的一行或多行时出一个现错误,则整个UPDATE操作被取消 (错误发生前更新的所有行被恢复到它们原来的值)。为即使是发生错误,也继续进行更新,可使用IGNORE关键字,如下所示: UPDATE IGNORE customers...

使用DELETE语句更新数据,大家也都很熟练了,一般DELETE语句组成部分如下:


1.在使用DELETE语句时,不要省略DELETE子句 ,否则会删除表中所有行。

2.DELETE语句从表中删除行,甚至是删除表中所有行。但是,DELETE不删除表本身。

3.如果想从表中删除所有行,不要使用DELETE。 可使用TRUNCATE TABLE语句,它完成相同的工作,但速度更快,因为TRUNCATE实际是删除原来的表并重新创建一个表,而不是逐行删除表中的数据

1.除非确实打算更新和删除每一行,否则绝对不要使用不带WHERE 子句的UPDATE或DELETE语句。

2.保证每个表都有主键(如果忘记这个内容,请参阅第15章),尽可能 像WHERE子句那样使用它(可以指定各主键、多个值或值的范围)。

3.在对UPDATE或DELETE语句使用WHERE子句前,应该先用SELECT进行测试,保证它过滤的是正确的记录,以防编写的WHERE子句不正确。

4.使用强制实施引用完整性的数据库(关于这个内容,请参阅第15
章),这样MySQL将不允许删除具有与其他表相关联的数据的行。

5.MySQL没有撤销(undo)按钮。应该非常小心地使用UPDATE和DELETE,否则你会发现自己更新或删除了错误的数据。

第二十一章 创建和操纵表

使用CREATE语句来创建一个表,大家都很熟悉了,如下图所示

需要注意的有以下几点:

1.在建表时,每一列要么是可为NULL列,要么是NOT NULL列,如果不指定,默认为可为NULL列。

2.主键必须保证唯一,不能为NULL。如果使用一个列作为主键,值必须唯一,如果使用多个列作为主键,那么多个列组合的值必须唯一。

3.MySQL有一个具体管理和处理数据的内部引擎,在执行SQL语句时,可以使用ENGINE语句指定引擎,如果省略ENGINE=语句,则使用默认引擎(很可能是MyISAM),以下为MySQL常见的几个引擎:

是一个可 靠的事 务 处 理 引 擎 ( 参 见 第 26 章 ), 它 不 支 持 全 文 本搜索;

在功能等同于MyISAM,但由于数据存储在内存(不是磁盘) 中,速度很快,所以特别适合于临时表;

是一个性能极高的引擎,它支持全文本搜索(参见第18章), 但不支持事务处理。

在表建立以后,如果需要对表结构进行修改,我们可以使用ALTER TABLE语句对表进行修改。例如:

复杂的表结构更改一般需要手动删除过程,它涉及以下步骤:

1.用新的列布局创建一个新表。

2.使用INSERT SELECT语句从旧表复制数据到新表。如果有必要,可使用转换函数和计算字段。

3.检验包含所需数据的新表。

4.重命名旧表(如果确定,可以删除它)。

5.用旧表原来的名字重命名新表。

6.根据需要,重新创建触发器、存储过程、索引和外键。

删除表(删除整个表而不是其内容)非常简单,使用DROP TABLE语,例如:

视图为虚拟的表。它们包含的不是数据而是根据需要检索数据的查 询。视图提供了一种MySQL的SELECT语句层次的封装,可用来简化数据 处理以及重新格式化基础数据或保护基础数据。


后面就可以把productcustomers视图看成一个虚拟表进行查询,如下图所示:

2.简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必 知道它的基本查询细节。

3.使用表的组成部分而不是整个表。

4.保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。

5.更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。

1.与表一样,视图必须唯一命名(不能给视图取与别的视图或表相 同的名字)。

2.对于可以创建的视图数目没有限制。

3.为了创建视图,必须具有足够的访问权限。这些限制通常由数据库管理人员授予。

4.视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造一个视图。

5.ORDER BY可以用在视图中,但如果从该视图检索数据SELECT中也含有ORDER BY,那么该视图中的ORDER BY将被覆盖。

6.视图不能索引,也不能有关联的触发器或默认值。

7.视图可以和表一起使用。例如,编写一条联结表和视图的SELECT语句。

4.更新视图时,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的视图不存在,则第2条更新语句会创建一个视图;如果要更新的视图存在,则第2条更新语句会替换原有视图。

我们上面的例子中视图的作用其实是简化复杂SQL的使用,其实视图还有其他的作用,例如:

用视图重新格式化检索出的数据

用视图过滤不想要的数据

视图是可更新的(也就是可以对它们使用INSERT、UPDATE和DELETE)。更新一个视图将更新其基表(可以回忆一下,视图本身没有数据)。如果你对视图增加或删除行,实际上是对其基表增加或删除行。但是当视图定义中有以下操作时,则不能进行视图的更新:

第二十三章 使用存储过程

存储过程,就是可以一条或多条MySQL语句的组合起来,并且可以加入一些业务逻辑。

使用CREATE PROCEDURE语句创建一个存储过程,对一个SELECT语句进行封装,之后可以使用CALL语句来执行这个存储过程。


需要注意的是,因为在存储过程中会包含一些;分隔符,而在命令行实用程序中,使用;字符来作为语句分隔符,为了避免语法错误,可以使用DELIMITER语句来定义一个新的语句结束分隔符。如下图所示:

在创建存储过程时,可以使用IN语句来存储传入参数,OUT语句来存储返回结果。
在下面这个例子中,20005是传入参数,@total是返回结果。传入参数和返回结果也可以定义多个。


在创建存储过程中,也可以使用IF,THEN,END IF语句来设置判断条件,这是存储过程与简单的语句封装最大的区别。


添加了另外一个 参数taxable,它是一个布尔值(如果要增加税则为真,否则为假)。在 存储过程体中,用DECLARE语句定义了两个局部变量。DECLARE要求指定 变量名和数据类型,它也支持可选的默认值(这个例子中的taxrate的默 认被设置为6%)。SELECT语句已经改变,因此其结果存储到total(局部 变量)而不是ototal。IF语句检查taxable是否为真,如果为真,则用另 一SELECT语句增加营业税到局部变量total。最后,用另一SELECT语句将 total(它增加或许不增加营业税)保存到ototal。
BOOLEAN值指定为1表示真,指定为0表示假(实际上,非零值 都考虑为真,只有0被视为假)。通过给中间的参数指定0或1,可以有条件地将营业税加到订单合计上。

游标(cursor)是一个存储在MySQL服务器上的数据库查询, 它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游 标之后,应用程序可以根据需要滚动或浏览结果集中的数据。

如果不明确关闭游标,MySQL将会在到达END语句时自动关闭它。



这个例子使用FETCH检索当前order_num到声明的名为o的变量中。但与前一个例子不一样的是,这个 例子中的FETCH是在REPEAT内,因此它反复执行直到done为真(由UNTIL done END REPEAT;规定)。为使它起作用,用一个DEFAULT 0(假,不结 束)定义变量done。当在 FETCH 语句中引用的游标位置处于结果表最后一行之后时,SQLSTATE会为02000,这个时候done会为真,停止循环。

第二十五章 使用触发器

创建触发器语句的格式一般是

可在一个操作发生之前或之后执行,这里给出了AFTER INSERT, 所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本Product added将对每个插入的行显示一次。

  1. 在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被 插入的行;
  2. 在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改 被插入的值);

DELETE触发器在DELETE语句执行之前或之后执行,在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行。OLD中的值全都是只读的,不能更新。

上面这个例子中,在任意订单被删除前将执行此触发器。它使用一条INSERT语句将OLD中的值(要被删除的订单)保存到一个名为archive_ orders的存档表中(为实际使用这个例子,你需要用与orders相同的列 创建一个名为archive_orders的表)。

UPDATE触发器在UPDATE语句执行之前或之后执行。在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问 以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新 更新的值。在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改 将要用于UPDATE语句中的值)。OLD中的值全都是只读的,不能更新。

上面面的例子保证州名缩写总是大写(不管UPDATE语句中给出的是大 写还是小写)

1.只有表才支持触发器,视图不支持(临时表也不 支持)。

2.如果BEFORE触发器失败,则MySQL将不执行请求的操作。此外,如果BEFORE触发器或语句本身失败,MySQL 将不执行AFTER触发器(如果有的话)。

3.与其他DBMS相比,MySQL 5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划。

4.创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关 的触发器也能执行。

5.应该用触发器来保证数据的一致性(大小写、格式等)。在触发器中执行这种类型的处理的优点是它总是进行这种处理,而且是透 明地进行,与客户机应用无关。

6.触发器的一种非常有意义的使用是创建审计跟踪。使用触发器, 把更改(如果需要,甚至还有之前和之后的状态)记录到另一个 表非常容易。

7.遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发 器内调用存储过程。所需的存储过程代码需要复制到触发器内。

第二十六章 管理事务处理

事务处理可以用来维护数据库的完整性,它保证一组SQL语句要么完全执行,要么完全不执行。利用事务处理,可以保证一组操作不会中途停止,它们 或者作为整体执行,或者完全不执行(除非明确指示)。如果没有错误发 生,整组语句提交给(写到)数据库表。如果发生错误,则进行回退(撤 销)以恢复数据库到某个已知且安全的状态。
提交(commit)指将未存储的SQL语句结果写入数据库表;
holder),你可以对它发布回退(与回退整个事务处理不同)。

一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交(implicit commit),即提交(写或保存)操作是自动进行的。但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交, 使用COMMIT语句。


在这个例子中,从系统中完全删除订单20010。因为涉及更新
两个数据库表orders和orderItems,所以使用事务处理块来 保证订单不被部分删除。最后的COMMIT语句仅在不出错时写出更改。如 果第一条DELETE起作用,但第二条失败,则DELETE不会提交(会被自动撤销)。

简单的ROLLBACK和COMMIT语句就可以写入或撤销整个事务处理。但 是,只是对简单的事务处理才能这样做,更复杂的事务处理可能需要部 分提交或回退。为了支持回退部分事务处理,必须能在事务处理块中合适的位置放 置占位符。这样,如果需要回退,可以回退到某个占位符。

默认的MySQL行为是自动提交所有更改。换句话说,任何 时候你执行一条MySQL语句,该语句实际上都是针对表执行的,而且所做 的更改立即生效。为指示MySQL不自动提交更改,可以使用

第二十七章 全球化和本地化

数据库表被用来存储和检索数据。不同的语言和字符集需要以不同 的方式存储和检索。因此,MySQL需要适应不同的字符集(不同的字母 和字符),适应不同的排序和检索数据的方法。

可以展示可用的字符集,MySQL 默认字符集是latin1,一般我们常用的就是utf8

可以展示所支持校对以及它们适用的字符集的完整列表,有的字符集具有不止一种校对。

通常系统管理在安装时定义一个默认的字符集和校对。此外,也可 以在创建数据库时,指定默认的字符集和校对。和校对,可以使用以下语句进行查看:


下确定使用什么样的字符集和校对。


此SELECT使用COLLATE指定一个备用的校对顺序(在这个例子 中,为区分大小写的校对)。除了这里看到的在ORDERBY子 句中使用以外,COLLATE还可以用于GROUP BY、HAVING、聚集 函数、别名等。

MySQL用户账号和信息存储在名为mysql的MySQL数据库中。

为看到赋予用户账号的权限,使用SHOW GRANTS FOR,如下图所示:

输出结果显示用户bforta有一个权限USAGE ON .。此结果表示在任意数据库和任意表上对任何数据没有权限。
用户定义为user@host MySQL的权限将会把用户名和主机名结合定义。如果不指定主机名,则使用默认的主机名%(授予用户访问权限而不管主机名)。

GRANT的反操作为REVOKE,用它来撤销特定的权限。

这条REVOKE语句取消刚赋予用户bforta的SELECT访问权限。被 撤销的访问权限必须存在,否则会出错。

GRANT和REVOKE可在几个层次上控制访问权限:

下面是可以授予或撤销的每个权限:

在使用GRANT和REVOKE时,用户账号必须存在, 但对所涉及的对象没有这个要求。这允许管理员在创建数据库 和表之前设计和实现安全措施。这样做的副作用是,当某个数据库或表被删除时(用DROP语 句),相关的访问权限仍然存在。而且,如果将来重新创建该 数据库或表,这些权限仍然起作用。

第二十九章 数据库维护

备份数据一般有以下几种方案:

1.使用命令行实用程序 mysqldump 转储所有数据库内容到某个外部 文件。在进行常规备份前这个实用程序应该正常运行,以便能正 确地备份转储文件。

2.可用命令行实用程序 mysqlhotcopy 从一个数据库复制所有数据 (并非所有数据库引擎都支持这个实用程序)。

3.可以使用 MySQL 的 BACKUP TABLE 或 SELECT INTO OUTFILE 转储所有数据到某个外部文件。这两条语句都接受将要创建的系统文件名,此系统文件必须不存在,否则会出错。数据可以用 RESTORE TABLE 来复原。

用来检查表键是否正确,返回的状态信息如下:

用来针对许多问题对表进行检查。在MyISAM表上还对索引进行检查。

检查自最后一次检查以来改动过的表

检查所有被删 除的链接并进行键检验

如果MyISAM表访问产生不正确和不一致的结果,可能需要用REPAIR TABLE来修复相应的表。这条语句不应该经常使用,如果需要经常使用,可能会有更大的问题要解决。
如果从一个表中删除大量数据,应该使用OPTIMIZE TABLE来收回所用的空间,从而优化表的性能。

服务器启动问题通常在对MySQL配置或服务器本身进行更改时出现。MySQL在这个问题发生时报告错误,但由于多数MySQL服务器是作为系统进程或服务自动启动的,这些消息可能看不到。
在排除系统启动问题时,首先应该尽量用手动启动服务器。MySQL 服务器自身通过在命令行上执行mysqld启动。下面是几个重要的mysqld命令行选项:

装载减去某些最佳配置的服务器

显示全文本消息(为获得更详细的帮助消息与--help联合使用)

MySQL维护管理员依赖的一系列日志文件。主要的日志文件有以下几种。

它包含启动和关闭问题以及任意关键错误的细节。此日志通常名为hostname.err,位于data目录中。此日志名可用 --log-error命令行选项更改。

它记录所有MySQL活动,在诊断问题时非常有用。此日志文件可能会很快地变得非常大,因此不应该长期使用它。此 日志通常名为hostname.log,位于data目录中。此名字可以用 --log命令行选项更改。

它记录更新过数据(或者可能更新过数据)的所有语句。此日志通常名为hostname-bin,位于data目录内。此名字 可以用--log-bin命令行选项更改。注意,这个日志文件是MySQL 5 中添加的,以前的MySQL版本中使用的是更新日志。

顾名思义,此日志记录执行缓慢的任何查询。这 个日志在确定数据库何处需要优化很有用。此日志通常名为 hostname-slow.log,位于data目录中。此名字可以用
--log-slow-queries命令行选项更改。 在使用日志时,可用FLUSH LOGS语句来刷新和重新开始所有日志文件。

1.首先,MySQL(与所有DBMS一样)具有特定的硬件建议。在学习和研究MySQL时,使用任何旧的计算机作为服务器都可以。但对用于生产的服务器来说,应该坚持遵循这些硬件建议。

2.一般来说,关键的生产DBMS应该运行在自己的专用服务器上。

3.MySQL是用一系列的默认设置预先配置的,从这些设置开始通常是很好的。但过一段时间后你可能需要调整内存分配、缓冲区大 小等。(为查看当前设置,可使用SHOW VARIABLES;和SHOW STATUS;)

4.MySQL一个多用户多线程的DBMS,换言之,它经常同时执行多个任务。如果这些任务中的某一个执行缓慢,则所有请求都会执 行缓慢。如果你遇到显著的性能不良,可使用SHOW PROCESSLIST 显示所有活动进程(以及它们的线程ID和执行时间)。你还可以用KILL命令终结某个特定的进程(使用这个命令需要作为管理员登录)。

5.总是有不止一种方法编写同一条SELECT语句。应该试验联结、并、子查询等,找出最佳的方法。

7.一般来说,存储过程执行得比一条一条地执行其中的各条MySQL语句更快

8.应该总是使用正确的数据类型。

9.决不要检索比需求还要多的数据。换言之,不要用SELECT *(除非你真正需要每个列)。

10.有的操作(包括INSERT)支持一个可选的DELAYED关键字,如果使用它,将把控制立即返回给调用程序,并且一旦有可能就实际执行该操作。

11.在导入数据时,应该关闭自动提交。你可能还想删除索引(包括FULLTEXT索引),然后在导入完成后再重建它们。

12.必须索引数据库表以改善数据检索的性能。确定索引什么不是一件微不足道的任务,需要分析使用的SELECT语句以找出重复的 WHERE和ORDER BY子句。如果一个简单的WHERE子句返回结果所花的时间太长,则可以断定其中使用的列(或几个列)就是需要索引的对象。

13.你的SELECT语句中有一系列复杂的OR条件吗?通过使用多条SELECT语句和连接它们的UNION语句,你能看到极大的性能改进。

14.索引改善数据检索的性能,但损害数据插入、删除和更新的性能。如果你有一些表,它们收集数据且不经常被搜索,则在有必要之前不要索引它们。(索引可根据需要添加和删除。)

16.数据库是不断变化的实体。一组优化良好的表一会儿后可能就面目全非了。由于表的使用和内容的更改,理想的优化和配置也会改变。

17.最重要的规则就是,每条规则在某些条件下都会被打破。

分享一些自己的连表总结

  • 多表查询原理:将多个表通过笛卡尔积形成一个虚表,再根据查询条件筛选符合条件的数据。

  • 在关系数据库中,数据分布在多个逻辑表中。 要获得完整有意义的数据集,需要使用连接来查询这些表
      • INNER JOIN:内连接,关键字在表中存在至少一个匹配时返回行。
      • left join : 左连接,返回左表中所有的记录以及右表中连接字段相等的记录。
      • right join : 右连接,返回右表中所有的记录以及左表中连接字段相等的记录。
      • inner join : 内连接,又叫等值连接,只返回两个表中连接字段相等的行。
    • cross join : 结果是笛卡尔积,就是第一个表的行数乘以第二个表的行数。
    • GROUP BY:全外连接, 子句必须放在 WHERE 子句中的条件之后,必须放在 ORDER BY 子句之前

每种连接类型指定SQL Server如何使用一个表中的数据来选择另一个表中的行

  • 内连接是SQL Server中最常用的连接之一。 内部联接子句用于查询来自两个或多个相关表的数据。
    • 其次,在 INNER JOIN 子句和连接谓词中指定第二个表( T2 )。 只有连接谓词计算为 TRUE 的行才包

**INNER JOIN **子句将表 T1 的每一行与表 T2 的行进行比较,以查找满足连接谓词的所有行对。 如果连接
谓词的计算结果为 TRUE ,则匹配
的 T1 和 T2 行的列值将合并为一个新行并包含在结果集中。

下图说明了两个结果集的内联接的结果:
使用两个 INNER JOIN 子句来查询三个表中的数据:

图中左右两边的表是有关联的,中间黄色的交互区就是他们两个关联表中关联的数据
使用INNER JOIN可以在两个有关联数据的表中把关联的数据查询出来

使用两个 INNER JOIN 子句来查询三个表中的数据:
INNER JOIN 关键字在表中存在至少一个匹配时返回行。

  • LEFT JOIN 子句用于查询来自多个表的数据。它返回左表中的所有行和右表中的匹配行
    如果在右表中找不到匹配的行,则使用 NULL 代替显示。

以下图说明了两个结果集的左连接结果:

下面的小案例左表(学生表)通过某列名在右表(成绩表)中查询出在相同列名中的一行数据

以下是上面左连接查询语句的查询结果:*

图中为空的格子是在右表(成绩表)中 没有该学生学号下的考试课程与成绩,所以默认返回了一个NULL值

对于 学生表中的每一行,查询将其与 成绩 表中的所有行进行比较。 如果一对行导致连接谓词计算为
TRUE ,则将组合这些行中的列值以形成新行,然后将其包含在结果集中。

  • 如果左表( T1 )中的行没有与来自 T2 表的任何匹配行,则查询将左表中的行的列值与来自右表的每个列

数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。

  • 1、 on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录。
  • 2、where 条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有 left join 的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

中,返回的结果集是相同的

RIGHT JOIN 子句组合来自两个或多个表的数据。

  • RIGHT JOIN 开始从**右表中选择数据并与左表中的行
    匹配。 RIGHT JOIN 返回一个结果集,该结果集包含右表中的所有行,无论是否具有左表中的匹配行。
    如果右表中的行没有来自右表的任何匹配行,则结果集中右表的列将使用 NULL 值。

CROSS JOIN 将第一个表(T1)中的每一行与第二个表(T2)中的每一行连接起来。 换句话说,交叉连接返回
两个表中行的笛卡尔积。 与INNER JOIN或LEFT JOIN不同,交叉连接不会在连接的表之间建立关系。

假设 T1 表包含三行: 1 , 2 和 3 , T2 表包含三行: A , B 和 C 。 CROSS JOIN 从第一个表(T1)获取一行,然后为第二个表(T2)中的每一行创建一个新行。 然后它对第一个
表(T1)中的下一行执行相同操作,依此类推


在此图中, CROSS JOIN 总共创建了 9 行。 通常,如果第一个表有 n 行,第二个表有 m 行,则交叉连接

自联接用于将表连接到自身(同一个表)。 它对于查询分层数据或比较同一个表中的行很有用。
自联接使用内连接或左连接子句。 由于使用自联接的查询引用同一个表,因此表别名用于为查询中的表

请注意,如果在不使用表别名的情况下在查询中多次引用同一个表,则会出现错误。

上面查询语句中两次引用表 T 。表别名 t1 和 t2 用于为 T 表分配不同的名称。

staffs 表存储员工信息,如身份证,名字,姓氏和电子邮件。 它还有一个名为 manager_id 的列,用
要获取工作汇报关系,请使用自联接,如以下查询中所示:

FULL OUTER JOIN当左表或右表中存在匹配项时,该命令将返回所有行。
以下SQL语句选择所有客户和所有订单:

果“Customers”中的某些行在“Orders”中没有匹配项,或者在“Orders”中的某些行在“Customers”中没有
匹配项,则这些行也将被列出。

除了基础题部分,本文还收集整理的MySQL面试题还包括如下知识点或题型:

  • MySQL高扩展高可用

varchar是变长而char的长度是固定的。如果你的内容是固定大小的,你会得到更好的性能。

DELETE命令从一个表中删除某一行,或多行,TRUNCATE命令永久地从表中删除每一行。

问题3:什么是触发器,MySQL中都有哪些触发器?
触发器是指一段代码,当触发某个事件时,自动执行这些代码。在MySQL数据库中有如下六种触发器:

  • FLOAT类型数据可以存储至多8位十进制数,并在内存中占4字节。

  • DOUBLE类型数据可以存储至多18位十进制数,并在内存中占8字节。

问题5:如何在MySQL种获取当前日期?

问题6:如何查询第n高的工资?

(提示:代码可以左右滑动)

此题考察的是MySQL数据类型。MySQL数据类型属于MySQL数据库基础,由此延伸出的知识点还包括如下内容:

  • MySQL事务处理、存储过程、触发器

  • 1、整数类型,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示1字节、2字节、3字节、4字节、8字节整数。任何整数类型都可以加上UNSIGNED属性,表示数据是无符号的,即非负整数。
    长度:整数类型可以被指定长度,例如:INT(11)表示长度为11的INT类型。长度在大多数场景是没有意义的,它不会限制值的合法范围,只会影响显示字符的个数,而且需要和UNSIGNED ZEROFILL属性配合使用才有意义。
    例子,假定类型设定为INT(5),属性为UNSIGNED ZEROFILL,如果用户插入的数据为12的话,那么数据库实际存储数据为00012。

  • DECIMAL可以用于存储比BIGINT还大的整型,能存储精确的小数。
    而FLOAT和DOUBLE是有取值范围的,并支持使用标准的浮点进行近似计算。
    计算时FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串进行处理。

  • VARCHAR用于存储可变长字符串,它比定长类型更节省空间。
    VARCHAR使用额外1或2个字节存储字符串长度。列长度小于255字节时,使用1字节表示,否则使用2字节表示。
    VARCHAR存储的内容超出设置的长度时,内容会被截断。
    CHAR是定长的,根据定义的字符串长度分配足够的空间。
    CHAR会根据需要使用空格进行填充方便比较。
    CHAR适合存储很短的字符串,或者所有值都接近同一个长度。
    CHAR存储的内容超出设置的长度时,内容同样会被截断。

对于经常变更的数据来说,CHAR比VARCHAR更好,因为CHAR不容易产生碎片。
对于非常短的列,CHAR比VARCHAR在存储空间上更有效率。
使用时要注意只分配需要的空间,更长的列排序时会消耗更多内存。
尽量避免使用TEXT/BLOB类型,查询时会使用临时表,导致严重的性能开销。

  • 4、枚举类型(ENUM),把不重复的数据存储为一个预定义的集合。
    有时可以使用ENUM代替常用的字符串类型。
    ENUM存储非常紧凑,会把列表值压缩到一个或两个字节。
    ENUM在内部存储时,其实存的是整数。
    尽量避免使用数字作为ENUM枚举的常量,因为容易混乱。
    排序是按照内部存储的整数

  • 5、日期和时间类型,尽量使用timestamp,空间效率高于datetime,
    用整数保存时间戳通常不方便处理。
    如果需要存储微妙,可以使用bigint存储。
    看到这里,这道真题是不是就比较容易回答了。

答:int(0)表示数据是INT类型,长度是0、char(16)表示固定长度字符串,长度为16、varchar(16)表示可变长度字符串,长度为16、datetime表示时间类型、text表示字符串类型,能存储大字符串,最多存储65535字节数据)

进入MySQL命令行后:G、c、q、s、h、d

c:取消当前MySQL命令

  • 默认事务型引擎,最重要最广泛的存储引擎,性能非常优秀。

  • 数据存储在共享表空间,可以通过配置分开。也就是多个表和索引都存储在一个表空间中,可以通过配置文件改变此配置。

  • 对主键查询的性能高于其他类型的存储引擎。

  • 内部做了很多优化,从磁盘读取数据时会自动构建hash索引,插入数据时自动构建插入缓冲区。

  • 通过一些机制和工具支持真正的热备份。

  • 支持崩溃后的安全恢复。

  • 拥有全文索引、压缩、空间函数。

  • 不支持事务和行级锁、不支持崩溃后的安全恢复。

  • 表存储在两个文件,MYD和MYI。

  • 设计简单,某些场景下性能很好,例如获取整个表有多少条数据,性能很高。

在大多数场景下建议使用InnoDB存储引擎。

表锁是日常开发中的常见问题,因此也是面试当中最常见的考察点,当多个查询同一时刻进行数据修改时,就会产生并发控制的问题。共享锁和排他锁,就是读锁和写锁。

  • 共享锁,不堵塞,多个用户可以同时读一个资源,互不干扰。

  • 排他锁,一个写锁会阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用户读取正在写入的资源。

  • 表锁,系统开销最小,会锁定整张表,MyIsam使用表锁。

  • 行锁,最大程度的支持并发处理,但是也带来了最大的锁开销,InnoDB使用行锁。

  • MySQL提供事务处理的表引擎,也就是InnoDB。

  • 服务器层不管理事务,由下层的引擎实现,所以同一个事务中,使用多种引擎是不靠谱的。

  • 需要注意,在非事务表上执行事务操作,MySQL不会发出提醒,也不会报错。

  • 为以后的使用保存的一条或多条MySQL语句的集合,因此也可以在存储过程中加入业务逻辑和流程。

  • 可以在存储过程中创建表,更新数据,删除数据等等。

  • 可以通过把SQL语句封装在容易使用的单元中,简化复杂的操作

提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程。

  • 可以通过数据库中的相关表实现级联更改。

  • 实时监控某张表中的某个字段的更改而需要做出相应的处理。

  • 例如可以生成某些业务的编号。

  • 注意不要滥用,否则会造成数据库及应用程序的维护困难。

  • 大家需要牢记以上基础知识点,重点是理解数据类型CHAR和VARCHAR的差异,表存储引擎InnoDB和MyISAM的区别。

  • InnoDB数据存储在共享表空间,MyISAM数据存储在文件中;

  • InnoDB支持崩溃后的恢复,MyISAM不支持;

  • InnoDB不支持全文索引,MyISAM支持全文索引;

问题9:innodb引擎的特性

  • 自适应哈希索引(ahi)

  • varchar可指定字符数,text不能指定,内部存储varchar是存入的实际字符数+1个字节(n255),text是实际字符数+2个字节。

  • text类型不能有默认值。

  • varchar可直接创建索引,text创建索引要指定前多少个字符。varchar查询速度快于text,在都创建索引的情况下,text的索引几乎不起作用。

  • 查询text需要创建临时表。

是指显示字符的长度,不影响内部存储,只是当定义了ZEROFILL时,前面补多少个 0

问题14:简单描述MySQL中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响?

此真题主要考察的是MySQL索引的基础和类型,由此延伸出的知识点还包括如下内容:

  • MySQL索引的创建原则

  • MySQL索引的注意事项

下面我们就来将这些知识一网打尽
  • 索引类似于书籍的目录,要想找到一本数的某个特定主题,需要先查找书的目录,定位对应的页码

  • 存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的值,然后根据匹配的索引找到对应的数据行。

  • 创建单个索引的语法:CREATE INDEX 索引名 on 表名(字段名)

  • 索引名一般是:表名_字段名

  • 创建联合索引的语法:CREATE INDEX 索引名 on 表名(字段名1,字段名2)

  • 其中index还可以替换成unique,primary key,分别代表唯一索引和主键索引

  • 大大减少服务器需要扫描的数据量。

  • 帮助服务器避免排序和临时表。

  • 将随机I/O变顺序I/O。

  • 降低写的速度(不良影响)。

  • 磁盘占用(不良影响)。

  • 对于非常小的表,大部分情况下全表扫描效率更高。

  • 中到大型表,索引非常有效。

  • 特大型的表,建立和使用索引的代价会随之增大,可以使用分区技术来解决。

索引很多种类型,是在MySQL的存储引擎实现的。

  • 普通索引:最基本的索引,没有任何约束限制。

  • 唯一索引:和普通索引类似,但是具有唯一性约束。

  • 主键索引:特殊的唯一索引,不允许有空值。

-一个表只能有一个主键索引,但是可以有多个唯一索引。

  • 主键索引一定是唯一索引,唯一索引不是主键索引。

  • 主键可以与外键构成参照完整性约束,防止数据不一致。

  • 联合索引:将多个列组合在一起创建索引,可以覆盖多个列。(也叫复合索引,组合索引)

  • 外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致性、完整性、和实现级联操作(基本不用)。

  • 全文索引:MySQL自带的全文索引只能用于MyISAM,并且只能对英文进行全文检索 (基本不用)

MySQL索引的创建原则

  • 最适合创建索引的列是出现在WHERE或ON子句中的列,或连接子句中的列而不是出现在SELECT关键字后的列。

  • 索引列的基数越大,数据区分度越高,索引的效果越好。

  • 对于字符串进行索引,应该制定一个前缀长度,可以节省大量的索引空间。

  • 根据情况创建联合索引,联合索引可以提高查询效率。

  • 避免创建过多的索引,索引会额外占用磁盘空间,降低写操作效率。

  • 主键尽可能选择较短的数据类型,可以有效减少索引的磁盘占用提高查询效率。

MySQL索引的注意事项
1、联合索引遵循前缀原则

2、LIKE查询,%不能在前

3、列值为空(NULL)时是可以使用索引的,但MySQL难以优化引用了可空列的查询,它会使索引、索引统计和值更加复杂。可空列需要更多的储存空间,还需要在MySQL内部进行特殊处理。

4、如果MySQL估计使用索引比全表扫描更慢,会放弃使用索引,例如:

5、如果关键词or前面的条件中的列有索引,后面的没有,所有列的索引都不会被用到。

6、列类型是字符串,查询时一定要给值加引号,否则索引失效,例如:
以上SQL语句能搜到,但无法用到索引。

  • MySQL索引是用一种叫做聚簇索引的数据结构实现的,下面我们就来看一下什么是聚簇索引。

  • 聚簇索引是一种数据存储方式,它实际上是在同一个结构中保存了B+树索引和数据行,InnoDB表是按照聚簇索引组织的(类似于Oracle的索引组织表)。

B+ 树是一种树数据结构,是一个n叉排序树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。
B+ 树通常用于数据库和操作系统的文件系统中。NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等文件系统都在使用B+树作为元数据索引。B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入。

InnoDB通过主键聚簇数据,如果没有定义主键,会选择一个唯一的非空索引代替,如果没有这样的索引,会隐式定义个主键作为聚簇索引。
下图形象说明了聚簇索引表(InnoDB)和普通的堆组织表(MyISAM)的区别:

最常问的MySQL面试题三——每个开发人员都应该知道
对于普通的堆组织表来说(右图),表数据和索引是分别存储的,主键索引和二级索引存储上没有任何区别。
而对于聚簇索引表来说(左图),表数据是和主键一起存储的,主键索引的叶结点存储行数据,二级索引的叶结点存储行的主键值。
聚簇索引表最大限度地提高了I/O密集型应用的性能,但它也有以下几个限制:

  • 1)插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。

  • 2)更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。

  • 3)二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

二级索引的叶节点存储的是主键值,而不是行指针,这是为了减少当出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空间。

在一些MySQL索引基础考题中,我们可以轻松的通过索引基础和类型来解决此类问题,对于一些索引创建注意事项方面的考点,我们可以通过索引创建原则和注意事项来解决。

问题14:创建MySQL联合索引应该注意什么?

问题15:列值为NULL时,查询是否会用到索引?
在MySQL里NULL值的列也是走索引的。当然,如果计划对列进行索引,就要尽量避免把它设置为可空,MySQL难以优化引用了可空列的查询,它会使索引、索引统计和值更加复杂。

MyISAM存储引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。MyISAM的索引方式也叫做非聚簇索引的,之所以这么称呼是为了与InnoDB的聚簇索引区分。

  • InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。

  • InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。

  • MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。

  • InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。

问题19:以下三条sql 如何建索引,只建一条怎么建?

  • MySQL的关联查询语句

针对刚才这道题,答案可以是如下两种形式的写法:

MySQL的关联查询语句

  • 左外连接:LEFT OUTER JOIN, 以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN

  • 右外连接:RIGHT OUTER JOIN, 以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN

  • 就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并

  • 如果使用UNION ALL,不会合并重复的记录行

  • MySQL不支持全连接

根据考题要搞清楚表的结果和多表之间的关系,根据想要的结果思考使用那种关联方式,通常把要查询的列先写出来,然后分析这些列都属于哪些表,才考虑使用关联查询

为了记录足球比赛的结果,设计表如下:
其中,match赛程表中的hostTeamID与guestTeamID都和team表中的teamID关联,查询到之间举行的所有比赛,并且用以下形式列出:拜仁 2:0 不莱梅

首先列出需要查询的列:
  • 主队 结果 客对 时间

初步写一个基础的SQL:

通过外键联表,完成最终SQL:

  • 如果使用UNION ALL,不会合并重复的记录行

问题23:一个6亿的表a,一个3亿的表b,通过外键tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录。

  • 1、如果A表TID是自增长,并且是连续的,B表的ID为索引

  • 2、如果A表的TID不是连续的,那么就需要使用覆盖索引.TID要么是主键,要么是辅助索引,B表ID也需要有索引。

问题24:拷贝表( 拷贝数据, 源表名:a 目标表名:b)

问题26:随机取出10条数据

问题27:请简述项目中优化SQL语句执行效率的方法,从哪些方面,SQL语句性能如何分析?
这道题主要考察的是查找分析SQL语句查询速度慢的方法

  • 优化查询过程中的数据访问

  • 优化特定类型的查询语句

如何查找查询速度慢的原因
记录慢查询日志,分析查询日志,不要直接打开慢查询日志进行分析,这样比较浪费时间和精力,可以使用pt-query-digest工具进行分析

有时根据这些计数,可以推测出哪些操作代价较高或者消耗时间多

观察是否有大量线程处于不正常的状态或特征

最常问的MySQL面试题五——每个开发人员都应该知道

优化查询过程中的数据访问

  • 访问数据太多导致查询性能下降

  • 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列

  • 确认MySQL服务器是否在分析大量不必要的数据行

  • 避免犯如下SQL语句错误

  • 查询不需要的数据。解决办法:使用limit解决

  • 多表关联返回全部列。解决办法:指定列名

  • 总是返回全部列。解决办法:避免使用SELECT *

  • 重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存

  • 是否在扫描额外的记录。解决办法:

  • 使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,可以通过如下技巧去优化:

  • 使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果。

  • 改变数据库和表的结构,修改数据表范式

  • 重写SQL语句,让优化器可以以更优的方式执行查询。

  • 一个复杂查询还是多个简单查询

  • MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多

  • 使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的。

  • 将一个大的查询分为多个小的相同的查询

  • 一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销。

  • 分解关联查询,让缓存的效率更高。

  • 执行单个查询可以减少锁的竞争。

  • 在应用层做关联更容易对数据库进行拆分。

  • 查询效率会有大幅提升。

优化特定类型的查询语句

  • count(*)会忽略所有的列,直接统计所有列数,不要使用count(列名)

  • 当有where条件时,MyISAM的count统计不一定比其它引擎快。

  • 可以使用explain查询近似值,用近似值替代count(*)

  • 确定ON或者USING子句中是否有索引。

  • 确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

  • 这两种查询据可以使用索引来优化,是最有效的优化方法

  • 关联查询中,使用标识列分组的效率更高

  • WITH ROLLUP超级聚合,可以挪到应用程序处理

  • LIMIT偏移量大的时候,查询效率较低

  • 可以记录上次查询的最大ID,下次查询时直接根据该ID来查询

对于此类考题,先说明如何定位低效SQL语句,然后根据SQL语句可能低效的原因做排查,先从索引着手,如果索引没有问题,考虑以上几个方面,数据访问的问题,长难查询句的问题还是一些特定类型优化的问题,逐一回答。

SQL语句优化的一些方法?

  • 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  • 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

  • 3.应尽量避免在 where 子句中使用!=或操作符,否则引擎将放弃使用索引而进行全表扫描。

  • 4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

  • 5.in 和 not in 也要慎用,否则会导致全表扫描,如:

  • 7. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

  • 8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

  • 9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

  • 10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

整理自网络、SQL数据库开发

添加好友,备注【交流
可私聊交流,也可进资源丰富学习群

我要回帖

更多关于 sql like多个值 的文章

 

随机推荐