数据结构论坛

首页 » 分类 » 定义 » Mysql数据库部分
TUhjnbcbe - 2024/8/22 16:32:00

面试中我们经常会被要求做一份笔试题,笔试题通过后会有技术大佬来面试我们。在笔试题最后一般都是有一道关于mysql语句的问题,让手写出增、删、改、查语句,今天我们就学习一下mysql语句。

数据表连接问题,左外连接、右外连接、内连接等

一、交叉连接(CROSSJOIN)

交叉连接(CROSSJOIN):有两种,显式的和隐式的,不带ON子句,返回的是两表的乘积,也叫笛卡尔积。

例如:下面的语句1和语句2的结果是相同的。

语句1:隐式的交叉连接,没有CROSSJOIN。

语句2:显式的交叉连接,使用CROSSJOIN。

语句1和语句2的结果是相同的,查询结果如下:

二、内连接(INNERJOIN)

内连接(INNERJOIN):有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行。(所谓的链接表就是数据库在做查询形成的中间表)。

例如:下面的语句3和语句4的结果是相同的。

语句3:隐式的内连接,没有INNERJOIN,形成的中间表为两个表的笛卡尔积。

语句4:显示的内连接,一般称为内连接,有INNERJOIN,形成的中间表为两个表经过ON条件过滤后的笛卡尔积。

语句3和语句4的查询结果:

三、外连接(OUTERJOIN):外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接(LEFTOUTERJOIN)、右外连接(RIGHTOUTERJOIN)和全外连接(FULLOUTERJOIN)。

三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:

左外连接还返回左表中不符合连接条件单符合查询条件的数据行。

右外连接还返回右表中不符合连接条件单符合查询条件的数据行。

全外连接还返回左表中不符合连接条件单符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外=左外UNION右外”。

说明:左表就是在“(LEFTOUTERJOIN)”关键字左边的表。右表当然就是右边的了。在三种类型的外连接中,OUTER关键字是可省略的。

下面举例说明:

语句5:左外连接(LEFTOUTERJOIN)

语句6:右外连接(RIGHTOUTERJOIN)

注意:WHERE条件放在ON后面查询的结果是不一样的。例如:

语句7:WHERE条件独立。

语句8:将语句7中的WHERE条件放到ON后面。

从语句7和语句8查询的结果来看,显然是不相同的,语句8显示的结果是难以理解的。因此,推荐在写连接查询的时候,ON后面只跟连接条件,而对中间表限制的条件都写到WHERE子句中。

语句9:全外连接(FULLOUTERJOIN)。

注意:MySQL是不支持全外的连接的,这里给出的写法适合Oracle和DB2。但是可以通过左外和右外求合集来获取全外连接的查询结果。下图是上面SQL在Oracle下执行的结果:

语句10:左外和右外的合集,实际上查询结果和语句9是相同的。

语句9和语句10的查询结果是相同的,如下:

四、联合连接(UNIONJOIN):这是一种很少见的连接方式。Oracle、MySQL均不支持,其作用是:找出全外连接和内连接之间差异的所有行。这在数据分析中排错中比较常用。也可以利用数据库的集合操作来实现此功能。

语句11:联合查询(UNIONJOIN)例句,还没有找到能执行的SQL环境。

语句12:语句11在DB2下的等价实现。还不知道DB2是否支持语句11呢!

语句13:语句11在Oracle下的等价实现。

五、自然连接(NATURALINNERJOIN):说真的,这种连接查询没有存在的价值,既然是SQL2标准中定义的,就给出个例子看看吧。自然连接无需指定连接列,SQL会检查两个表中是否相同名称的列,且假设他们在连接条件中使用,并且在连接条件中仅包含一个连接列。不允许使用ON语句,不允许指定显示列,显示列只能用*表示(ORACLE环境下测试的)。对于每种连接类型(除了交叉连接外),均可指定NATURAL。下面给出几个例子。

语句14:

语句15:

语句16:

语句17:

六、SQL查询的基本原理:两种情况介绍。

第一、单表查询:根据WHERE条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的);然后根据SELECT的选择列选择相应的列进行返回最终结果。

第二、两表连接查询:对两表求积(笛卡尔积)并用ON条件和连接连接类型进行过滤形成中间表;然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。

第三、多表连接查询:先对第一个和第二个表按照两表连接做查询,然后用查询结果和第三个表做连接查询,以此类推,直到所有的表都连接上为止,最终形成一个中间的结果表,然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。

理解SQL查询的过程是进行SQL优化的理论依据。

七、ON后面的条件(ON条件)和WHERE条件的区别:

ON条件:是过滤两个链接表笛卡尔积形成中间表的约束条件。

WHERE条件:在有ON条件的SELECT语句中是过滤中间表的约束条件。在没有ON的单表查询中,是限制物理表或者中间查询结果返回记录的约束。在两表或多表连接中是限制连接形成最终中间表的返回结果的约束。

从这里可以看出,将WHERE条件移入ON后面是不恰当的。推荐的做法是:

ON只进行连接操作,WHERE只过滤中间表的记录。

八、总结

连接查询是SQL查询的核心,连接查询的连接类型选择依据实际需求。如果选择不当,非但不能提高查询效率,反而会带来一些逻辑错误或者性能低下。下面总结一下两表连接查询选择方式的依据:

1、查两表关联列相等的数据用内连接。

2、Col_L是Col_R的子集时用右外连接。

3、Col_R是Col_L的子集时用左外连接。

4、Col_R和Col_L彼此有交集但彼此互不为子集时候用全外。

5、求差操作的时候用联合查询。

多个表查询的时候,这些不同的连接类型可以写到一块。例如:

上面这个SQL查询是多表连接的一个示范。

同上

sql语句优化

1.查询的模糊匹配

尽量避免在一个复杂查询里面使用LIKE%parm1%——红色标识位置的百分号会导致相关列的索引无法使用,最好不要用。

解决办法:

其实只需要对该脚本略做改进,查询速度便会提高近百倍。改进方法如下:

a、修改前台程序——把查询条件的供应商名称一栏由原来的文本输入改为下拉列表,用户模糊输入供应商名称时,直接在前台就帮忙定位到具体的供应商,这样在调用后台程序时,这列就可以直接用等于来关联了。

b、直接修改后台——根据输入条件,先查出符合条件的供应商,并把相关记录保存在一个临时表里头,然后再用临时表去做复杂关联。

2.索引问题

在做性能跟踪分析过程中,经常发现有不少后台程序的性能问题是因为缺少合适索引造成的,有些表甚至一个索引都没有。这种情况往往都是因为在设计表时,没去定义索引,而开发初期,由于表记录很少,索引创建与否,可能对性能没啥影响,开发人员因此也未多加重视。然一旦程序发布到生产环境,随着时间的推移,表记录越来越多。这时缺少索引,对性能的影响便会越来越大了。

法则:不要在建立的索引的数据列上进行下列操作:

避免对索引字段进行计算操作

避免在索引字段上使用not,,!=

避免在索引列上使用ISNULL和ISNOTNULL

避免在索引列上出现数据类型转换

避免在索引字段上使用函数

避免建立索引的列中使用空值

3.复杂操作

部分UPDATE、SELECT语句写得很复杂(经常嵌套多级子查询)——可以考虑适当拆成几步,先生成一些临时数据表,再进行关联操作。

4.update

同一个表的修改在一个过程里出现好几十次,如:

这类脚本其实可以很简单就整合在一个UPDATE语句来完成(前些时候在协助xxx项目做性能问题分析时就发现存在这种情况)

5.在可以使用UNIONALL的语句里,使用了UNION

UNION因为会将各查询子集的记录做比较,故比起UNIONALL,通常速度都会慢上许多。一般来说,如果使用UNIONALL能满足要求的话,务必使用UNIONALL。还有一种情况大家可能会忽略掉,就是虽然要求几个子集的并集需要过滤掉重复记录,但由于脚本的特殊性,不可能存在重复记录,这时便应该使用UNIONALL,如xx模块的某个查询程序就曾经存在这种情况,见,由于语句的特殊性,在这个脚本中几个子集的记录绝对不可能重复,故可以改用UNIONALL)。

6.在WHERE语句中,尽量避免对索引字段进行计算操作

这个常识相信绝大部分开发人员都应该知道,但仍有不少人这么使用,我想其中一个最主要的原因可能是为了编写写简单而损害了性能,那就不可取了。9月份在对XX系统做性能分析时发现,有大量的后台程序存在类似用法,如:wheretrunc(create_date)=trunc(:date1),虽然已对create_date字段建了索引,但由于加了TRUNC,使得索引无法用上。此处正确的写法应该是wherecreate_date=trunc(:date1)andcreate_datepre=或者是wherecreate_datebetweentrunc(:date1)andtrunc(:date1)+1-1/(24*60*60)。

注意:因between的范围是个闭区间(greaterthanorequaltolowvalueandlessthanorequaltohighvalue.),故严格意义上应该再减去一个趋于0的小数,这里暂且设置成减去1秒(1/(24*60*60)),如果不要求这么精确的话,可以略掉这步。

7.对Where语句的法则

7.1避免在WHERE子句中使用in,notin,or或者having。

可以使用exist和notexist代替in和notin。

可以使用表链接代替exist。Having可以用where代替,如果无法代替可以分两步处理。

7.2不要以字符格式声明数字,要以数字格式声明字符值。(日期同样)否则会使索引无效,产生全表扫描。

例子使用:

--不要使用:

8.对Select语句的法则

在应用程序、包和过程中限制使用select*fromtable这种方式。看下面例子,需要用到哪些字段就去查哪些字段不要都差,表里查数据很浪费时间。

--使用

--而不要使用

9.排序

避免使用耗费资源的操作,带有DISTINCT,UNION,MINUS,INTERSECT,ORDERBY的SQL语句会启动SQL引擎执行,耗费资源的排序(SORT)功能.DISTINCT需要一次排序操作,而其他的至少需要执行两次排序。

10.临时表

慎重使用临时表可以极大的提高系统性能。

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

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

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询(在项目开发中,一开始我写的查询语句加了null判断,一位前辈指点我要多思考,无论是代码还是库表,应遵‘循精简有效‘的原则):

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

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

可以这样查询:

15.in和notin也要慎用,否则会导致全表扫描,如:

selectidfromtwherenumin(1,2,3)

对于连续的数值,能用between就不要用in了:

selectidfromtwherenumbetween1and3

16.下面的查询也将导致全表扫描:

selectidfromtwherenamelike%abc%

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

selectidfromtwherenum/2=

应改为:

selectidfromtwherenum=*2

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

selectidfromtwheresubstring(name,1,3)=abc--name以abc开头的id

selectidfromtwherenamelikeabc%

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

20.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,

否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

21.不要写一些没有意义的查询,如需要生成一个空表结构:

selectcol1,col2into#tfromtwhere1=0

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

createtable#t(...)

22.很多时候用exists代替in是一个好的选择:

selectnumfromawherenumin(selectnumfromb)

用下面的语句替换:

selectnumfromawhereexists(select1frombwherenum=a.num)

23.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,

如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

24.索引并不是越多越好,索引固然可以提高相应的select的效率,但同时也降低了insert及update的效率,

因为insert或update时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。

一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

25.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。

这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

26.尽可能的使用varchar代替char,因为首先变长字段存储空间小,可以节省存储空间,

其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

27.任何地方都不要使用select*fromt,用具体的字段列表代替“*”,不要返回用不到的任何字段。

28.避免频繁创建和删除临时表,以减少系统表资源的消耗。

29.在新建临时表时,如果一次性插入数据量很大,那么可以使用selectinto代替createtable,避免造成大量log,

以提高速度;如果数据量不大,为了缓和系统表的资源,应先createtable,然后insert。

30.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

31.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

32.尽量避免大事务操作,提高系统并发能力。

33.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

什么是存储过程

存储过程是由流控制和SQL语句书写的过程,这个过程经编译和优化后存储在数据库服务器中,应用程序使用时只要调用即可。在ORACLE中,若干个有联系的过程可以组合在一起构成程序包。

存储过程优点

1.速度快。存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。

2.写程序简单。采用存储过程调用类,调用任何存储过程都只要1-2行代码。

3.升级、维护方便。存储过程会使得维护起来更加方便,因为通常修改一个存储过程要比在一个已经发布的组件中修改SQL语句更加方便;

4.能够缓解网络带宽。因为可以批量执行SQL语句而不是从客户端发送超负载的请求。尤其对于较为复杂的逻辑,减少了网络流量之间的消耗。

5.可保证数据的安全性和完整性。通过存储过程可以使没有权限的用户在控制之下间接地存取数据库,从而保证数据的安全。通过存储过程可以使相关的动作在一起发生,从而可以维护数据库的完整性。

6.增强安全性。

a)通过向用户授予对存储过程(而不是基于表)的访问权限,它们可以提供对特定数据的访问。

b)提高代码安全,防止SQL注入(但未彻底解决,例如,将数据操作语言--DML,附加到输入参数)。

c)SqlParameter类指定存储过程参数的数据类型,作为深层次防御性策略的一部分,可以验证用户提供的值类型(但也不是万无一失,还是应该传递至数据库前得到附加验证)。

存储过程缺点

1.可移植性差。由于存储过程将应用程序绑定到SQLServer,因此使用存储过程封装业务逻辑将限制应用程序的可移植性。如果应用程序的可移植性在您的环境中非常重要,则将业务逻辑封装在不特定于RDBMS的中间层中可能是一个更佳的选择。

2.代码可读性差,相当难维护。

3.不支持群集

4.大量采用存储过程进行业务逻辑的开发致命的缺点是很多存储过程不支持面向对象的设计,无法采用面向对象的方式将业务逻辑进行封装,从而无法形成通用的可支持复用的业务逻辑框架。

5.如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

使用原则

1.当一个业务同时对多个表进行处理的时候采用存储过程比较合适。

2.复杂的数据处理用存储过程比较合适,如有些报表处理。

3.多条件多表联合查询,并做分页处理,用存储过程也比较适合。

4.使用存储过程,等需求变动,需要维护的时候,麻烦就来了。不应该大规模使用。

5.适当的使用存储过程,能够提高我们SQL查询的性能,以便于提高我们的工作效率。

说说mysql和oracle他门的分页查询.分别是怎么实现的

MySQL:

1.MySQL数据库实现分页比较简单,提供了LIMIT函数。一般只需要直接写到sql语句后面就行了。

2.LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数,第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数。例如:

select*fromtableWHERE…LIMIT10;#返回前10行

select*fromtableWHERE…LIMIT0,10;#返回前10行

select*fromtableWHERE…LIMIT10,20;#返回第10-20行数据

Oracle:

在oracle中没有limit关键字,但是有rownum字段,rownum是一个伪列,是oracle系统自动为查询返回结果的每行分配的编号,第一行为1,第二行为2,以此类推..

1.第一种代码如下:

l其中最内层的查询SELECT*FROMTABLE_NAME表示不进行翻页的原始查询语句。ROWNUM=40和RN=21控制分页查询的每页的范围。

l上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHEREROWNUM=40这句上。

l选择第21到40条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM=40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHEREROWNUM=40语句,在查询的最外层控制分页的最小值和最大值。

2.第二种代码如下:

l红色部分:按照工资降序排序并查询所有的信息。

l棕色部分:得到红色部门查询的值,并查询出系统的rownum并指定上别名。这一句就比较关键,起了一个过渡的作用,首先要算出rownum来对红色部分指定上序号,也可以为蓝色外面部分用到这个变量。指定上查询的开始记录数和结束记录的条件。

l蓝色部分:指定记录从第几条开始到第几条结束,取出棕色部门的值来作为查询条件的变量

总结:绝大多数的情况下,第一个查询的效率比第二个高得多。

oracle如果要实现主键自增.怎么实现?mysql呢

要实现主键的自动递增非常简单.只需要在主键定义的后面加上auto_increment即可,

1.建立一个表,

2.建立一个sequence序列:

3.建立一个触发器:

数据库优化:电商项目中设计某个商品表的过程当中,为什么要按照下图设计

1.数据细分:

电商项目一般有三个主要业务:查询、下单和付款,其中下单只涉及商品id、商品价格、商品数量和商品金额,将这四个属性单独创建一张表,可以降低查询和下单业务之间的影响,必要的话,还可以将查询和下单拆分成两个独立的系统。

2.数据安全:

商品金额是计算好保存到数据库的,在使用时不用去界面获取,防止有人恶意篡改界面数据。很多电商网站如果涉及不严密就有可乘之机,虚假传递数据扰乱后台判断。

总之,写好一个sql语句并不只是单单查询结果正确就万事大吉了,在查询结果正确的前提下,要优化sql语句,提高效率。写好sql语句并不是一朝一夕,需要日积月累,下一个项目开发过程中,肯定比上一个项目做的要好,不断开发,不断学习,加油!!!

1
查看完整版本: Mysql数据库部分