面试篇三:数据库MySQL、Oracle

  • MySQL
  • MySQL分页查询
SELECT * FROM admin_company LIMIT 0,10;
SELECT * FROM admin_company ORDER BY id LIMIT 0,10;

limit后参数代表什么意思?

LIMIT[位置偏移量,]行数,第一个参数是从哪个序号加上,初始是0,第二个参数是查询多少行记录。

还有没有其他方式?

  • MySQL怎么查看执行计划

用explain,如 SELECT * FROM admin_company 

https://www.cnblogs.com/scorpio-cat/p/12661216.html

MySQL索引

索引分类:主键索引、唯一索引、普通索引、全文索引、组合索引。

MySQL默认会对主键和唯一键列创建索引。

       MySQL在创建表时就会创建一主键索引。如果主键存在,则存主键;如果主键不存在,但唯一键存在;如果主键和唯一健都不存在,则存6个字节的rowid。

索引的优点:减少服务器需要扫描的数据量、帮助服务器避免排序和临时表、将随机io变成顺序io。

索引匹配方式:

(1)全值匹配:where条件为=。

(2)最左前缀匹配:组合索引时,SQL必须包括组合索引指定的第一列;如果不存在,则不会走索引。

(3)列前缀匹配:使用like模糊查询,like ‘123%‘。

(4)范围值匹配:between and,> , <,但是索引中,如果包括了范围判断,则会导致后面的查询条件不走索引,只有前面的列和该范围列走索引。

(5)精确匹配某一列并范围匹配另一列。

(6)只访问索引的查询。

https://www.cnblogs.com/scorpio-cat/p/12661379.html

  • Oracle
  • Oracle分页查询
SELECT * FROM
    (SELECT ROWNUM rn ,* FROM admin_company WHERE rn <= 10)
 WHERE rn > 0;

没有ORDER BY,两层查询;如果要排序使用上面两层查询,会出现什么问题?查询结果有问题。

ROWNUM伪列产生的序号是按照数据被查询出来的顺序添加上去的,第一条是1,第二条是2,依次加1。

在ORACLE中使用rownum伪列分页时,需要多加一层查询,以保证rownum序号的连续性。

SELECT * FROM 
  (SELECT ROWNUM rn , c.* FROM
    (SELECT * FROM admin_company ORDER BY companyno) c WHERE rn <= 10
  )
 WHERE rn > 0;

当将一条语句交给查询优化器处理时:

如果排序列上有索引,则借助索引去查询数据,这样,读取出来的数据和rownum产生的序号是一种正常的对应关系。

如果排序列上没有索引,则使用全表扫描的方式,依次从表中读取数据,读取完成后,最后进行排序,可能产生的rownum序号不连续。

正是由于排序列上不一定有索引,所以在ORACLE中使用rownum伪列分页时,需要多加一层查询,以保证rownum序号的连续性。

  •  Oracle怎么查询执行计划

(1)通过使用工具PLSQL Developer中的Explain Plan Window窗口查看SQL执行计划。快捷键为F5。

(2)通过explain plan for explain plan for select *admin_company;

索引

作用:提高查询速度、确保数据的唯一性、可以加速表和表之间的连接,实现表和表之间的参照完整性、使用分组和排序子句进行数据检索时,可以减少分组和排序的时间、全文检索字段进行搜素优化。

分类:主键索引(PRIMAY KEY)、唯一索引(UNIQUE)、常规索引(INDEX)、全文索引(FULLTEXT)。

主键索引的几种创建方式:确保数据记录的唯一性,主键索引只能有一个。(以下为MYSQL示例)

CREATE TABLE mytable (
  ID INT(11) AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR (16) NOT NULL
  #或 PRIMARY KEY(`ID`)
) ;

唯一索引的几种创建方式:避免同一个表中某数据列中的值重复,唯一索引可有多个。(以下为MYSQL示例)

(1)创建索引:  CREATE UNIQUE INDEX indexName ON mytable(username(length));  

(2)修改表结构:  ALTER table mytable ADD UNIQUE [indexName] (username(length));  

(3)创建表时指定:

CREATE TABLE mytable (
  ID INT NOT NULL,
  username VARCHAR (16) NOT NULL,
  UNIQUE [ indexName ] (username (LENGTH)) 
  # 或者username VARCHAR(16) NOT NULL UNIQUE
) ;

常规索引的几种创建方式:快速定位特定数据,应加在查询条件的字段,不易添加太多常规索引,影响数据的插入,删除和修改操作,使用KEY或INDEX关键字设置。(以下为MYSQL示例)

(1)创建表时添加:

CREATE TABLE mytable (
  ID INT NOT NULL,
  userno VARCHAR (16) NOT NULL,
  username VARCHAR (16) NOT NULL,
  loginname VARCHAR (16) NOT NULL,
  INDEX `index1` (userno, username),
  KEY `index2` (userno, loginname)
) ;

(2)创建后追加:  ALTER TABLE `mytable` ADD INDEX `ind` (`userno`,`username`);  

全文索引的几种创建方式:快速定位特定数据,只能用于MyISAM类型的数据表,只能用于CHAR ,VARCHAR,TEXT数据列类型。(以下为MYSQL示例)

(1)创建表时添加:

CREATE TABLE mytable(
 username VARCHAR (16) NOT NULL,
 FULLTEXT(`username`)
)ENGINE=MYISAM;

(2)创建后追加:  ALTER TABLE mytable ADD FULLTEXT(`username`); 

SQL怎么优化执行效率更高、SQL优化经验

(1)SELECT子句中避免使用‘*’:Oracle在解析的过程中, 会将‘*’依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。

(2)使用表的别名(Alias): 当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上。这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。

(3)用IN来替换OR、用UNION替换OR (适用于索引列)、用EXISTS替代IN、用NOT EXISTS替代NOT IN。

(4)如果不需要去重,用UNION-ALL 替换UNION:UNION 将对结果集合进行合并和排序,这个操作会使用到SORT_AREA_SIZE这块内存,UNION ALL 将重复输出两个结果集合中相同记录,排序也不是必要的,效率就会因此得到提高。

(5)优化GROUP BY:提高GROUP BY 语句的效率,可以通过将不需要的记录在GROUP BY 之前过滤掉。

(6)使用DECODE函数来减少处理时间。【TODO】

(7)用Where子句替换HAVING子句:HAVING 只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序,总计等操作。

(8)合理使用索引:

①避免在索引列上使用NOT,当Oracle“遇到”NOT,他就会停止使用索引转而执行全表扫描。

②避免在索引列使用 !=、||、+,WHERE子句中,优化器将不使用索引而使用全表扫描。

③避免在索引列上使用计算。WHERE子句中,如果索引列是函数的一部分。优化器将不使用索引而使用全表扫描。

④避免在索引中使用任何可以为空的列,Oracle将无法使用该索引。对于单列索引,如果列包含空值,索引中将不存在此记录。对于复合索引,如果每个列都为 空,索引中同样不存在此记录。如果至少有一个列不为空,则记录存在于索引中。

⑤总是使用索引的第一个列:如果索引是建立在多个列上,只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引。这也是一条简单而重要的规则,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略 了索引。 

⑥避免对WHERE子句的列名使用函数(避免改变索引列的类型):当比较不同数据类型的数据时,如:

SELECT * FROM EMP WHERE EMPNO = TO_NUMBER(‘123‘); #类型转换没有发生在索引列上,索引的用途没有被改
SELECT * FROM EMP WHERETO_NUMBER(EMP_TYPE)=123; #类型转换没有发生在索引列上,索引的用途没有被改变