1. 为什么一定要设置主键?
其实这个不是一定的, 在有些场景下, 小系统或者没什么用的表不设置主键也没关系, mysql最好是使用自增主键, 主要是有以下两个原因:
如果定义了主键,那么InnoDB会选择主键作为聚集索引,如果没有显式定义主键,则InnoDB会选择第一个不包含Null值的唯一索引作为主键索引,如果也没有这样的唯一索引,则InnoDB会选择内置6字节长度的RowID作为隐含的聚集索引。所以反正都要生成一个主键,那还不如自己指定一个主键,提高查询效率。
2. 主键是用自增还是UUID?
最好是用自增主键,主要有以下两个原因:
1. 如果表使用自增主键,那么每次插入新的数据,数据就会顺序添加到当前索引节点的后续位置,当索引页写满后,就会自动开辟一个新的索引页。
2. 如果使用非自增主键(如UUID),由于每次插入主键的值都近似于随机,因此每次新记录都要被插入到索引页的随机某个位置,此时MySQL为了将新记录插入到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这样增加了很多开销,同事频繁的移动,分页操作会造成索引碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZETABLE来重建表并优化填充页面。
不过也不是所有场景下都得使用自增主键,可能有些场景下主键必须自己生成,不在乎那些性能的开销那也没有问题。
3. 自增主键用完了怎么办?
在MySQL中int整型的范围(-2147483648~2147483648)越20亿!因此不用考虑自增ID达到最大值的问题,如果数据量达到了千万级的时候就应该考虑分库分表了。
4. 主键为什么不推荐有业务含义?
最好是主键是无意义的自增ID,然后另外创建一个业务主键ID,因为任何有业务含义的列都有改变的可能性。主键一旦带上了业务含义,那么主键就有可能发生改变。主键一旦发生改变,该数据在磁盘上的存储位置就会发生变更,有可能会引发索引页分裂,产生空间碎片。
还有就是,带有业务含义的主键,不一定是顺序自增的。那么就会导致数据的插入顺序不能保证后面插入数据的主键一定比前面的数据大。如果出现了,后面插入数据的主键比前面的小,就有可能引发索引页分裂,产生空间碎片。
5. 货币字段用什么类型?
货币字典一般都用Decimal类型。
float和double是以二进制存储的,数据量大的时候可能存在误差。
6. 时间字段用什么类型?
这个看具体情况和实际场景,timestamp,datatime,bigint都行!
timestamp:该类型是四个字节的整数,它能表示的时间范围为1970-01-01 08:00:01到2038-01-19 11:14:07。2038年以后的时间是无法用timestamp类型存储的。但是它有一个优势,timestamp类型是带有时区信息的,一旦系统中的时区发生改变,例如修改了时区时,该字段的值就会自动变更。这个特性可以用来做一些国际化大项目,跨时区的应用。
datatime:占用8个字节,它存储的时间范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。显然存储的时间范围更大。但是它坑的地方在于,它存储的是时间绝对值,不带有时区信息。如果你改变了数据库的时区,该值不会自动变更。
bigint:也是8个字节,自己维护一个时间戳,查询效率高,并且使用它进行时间排序以及日期对比等操作时效率非常高,跨系统也很方便,毕竟存放的是数字。缺点也很明显,就是数据的可读性太差,无法直观的看到具体的时间,数据写入和读取时都需要做转换。
7. 为什么不直接存储图片、音频、视频等大容量内容?
我们在实际应用中都是以文件形式存储的。在MySQL中,只存文件的路径。虽然MySQL中Blob类型可以用来存放大容量文件,但是我们在生产中基本不用!主要有以下几个原因:
1. MySQL内存临时表不支持Text、Blob这样大数据类型,如果查询中包含这样的数据,查询效率会非常慢。
2. 数据库会变得特别大,内存占用率高,维护也比较麻烦。
3. binlog文件太大,如果是主从同步架构,会导致主从同步效率问题。
因此不推荐使用Blob等类型!
8. 表中有大字段X(例如:text类型),且字段X不会经常更新,以读为主,那么是拆成字表好?还是放在一起好?
其实各有利弊,拆开带来的问题:连接消耗;
不拆带来的问题:查询性能;
所以要看实际情况,如果表数据量比较大,最好还是拆开好,这样查询速度会更快。
9. 字段为什么要定义为Not Null?
一般情况,都会设置一个默认值,不会出现字段里面有Null,又有空的情况。主要有以下几个原因:
1.索引性能不好,MySQL难以优化索引可空列查询,它会使索引,索引统计和值更加复杂。可空列需要更多的存储空间,还需要MySQL内部进行特殊处理。可空列被索引后,每一条记录都需要一个额外的字节,还能导致Myisam中固定大小的索引变成可变大小的索引。
2.如果列中存在null的情况,可能导致count()函数执行不对的情况。
3.sql语句写起来也麻烦,既要判断为空,又要判断为null等。
10. where执行顺序是怎样的?
where 条件从左往右执行的,在数据量小的时候不用考虑,但数据量多的时候要考虑条件的先后顺序,此时应遵守一个原则:排除越多的条件放在第一个。
11. 应该在这些列上创建索引:
在经常需要搜索的列上,可以加快搜索的速度;在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
12. mysql联合索引
联合索引是两个或更多个列上的索引。对于联合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部分,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持a 、 a,b 、 a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知 道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。
13.什么是最左前缀原则?
最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如下:
select * from user where name=xx and city=xx ; //可以命中索引 select * from user where name=xx ; // 可以命中索引 select * from user where city=xx ; // 无法命中索引
sql
这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 city= xx and name =xx,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDER BY子句也遵循此规则。
14. sql语句应该考虑哪些安全性
1.防止sql注入,对特殊字符进行转义,过滤或者使用预编译sql语句绑定
2.使用最小权限原则,特别是不要使用root账户,微不同的动作或者操作建立不同的账户
3.当sql出错时,不要把数据库出错的信息暴露到客户端
15. mysql_fetch_array和mysql_fetch_object的区别是什么?
以下是mysql_fetch_array和mysql_fetch_object的区别:
mysql_fetch_array() - 将结果行作为关联数组或来自数据库的常规数组返回。
mysql_fetch_object - 从数据库返回结果行作为对象。
16. MySQL数据库cpu飙升到100%的话怎么处理?
1. 列出所有进程 show processlist 观察所有进程 多秒没有状态变化的(干掉)
2. 查看慢查询,找出执行时间长的sql;explain分析sql是否走索引,sql优化;
3. 检查其他子系统是否正常,是否缓存失效引起,需要查看buffer命中率;
4. 开启慢查询日志,查看慢查询的 SQL。
17. MyISAM 和 InnoDB 的基本区别?索引结构如何实现?
MyISAM类型不支持事务,表锁,易产生碎片,要经常优化,读写速度较快,而InnoDB类型支持事务,行锁,有崩溃恢复能力。读写速度比MyISAM慢,适合插入和更新操作比较多的应用,占空间大。
创建索引:alert table tablename add index (字段名
)
18. mysql中表锁和行锁的区别
在开发的时候,应该很少会注意到这些锁的问题,也很少会给程序加锁(除了库存这些对数量准确性要求极高的情况下),即使我们不会这些锁知识,我们的程序在一般情况下还是可以跑得好好的。因为这些锁数据库隐式帮我们加了,只会在某些特定的场景下才需要手动加锁。
对于UPDATE、DELETE、INSERT语句,InnoDB会自动给涉及数据集加排他锁(X) MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行增、删、改操作前,会自动给涉及的表加写锁,这个过程并不需要用户干预Mysql有很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁;这些锁统称为悲观锁(Pessimistic Lock)
行锁
特点:锁的粒度小,发生锁冲突的概率低、处理并发的能力强;开销大、加锁慢、会出现死锁不同的存储引擎支持的锁粒度是不一样的。InnoDB行锁和表锁都支持、MyISAM只支持表锁!InnoDB只有通过索引条件检索数据才使用行级锁,否则,InnoDB使用表锁也就是说,InnoDB的行锁是基于索引的!
InnoDB和MyISAM有两个本质的区别:InnoDB支持行锁、InnoDB支持事务
共享锁(S锁、读锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。即多个客户可以同时读取同一个资源,但不允许其他客户修改。
排他锁(X锁、写锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的读锁和写锁。写锁是排他的,写锁会阻塞其他的写锁和读锁。
另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁:
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。意向锁也是数据库隐式帮我们做了,不需要程序员关心!
加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁。
表锁
特点:开销小、加锁快、无死锁;锁粒度大,发生锁冲突的概率高,高并发下性能低加锁的方式:自动加锁。查询操作(SELECT),会自动给涉及的所有表加读锁,更新操作(UPDATE、DELETE、INSERT),会自动给涉及的表加写锁。如果某个进程想要获取读锁,同时另外一个进程想要获取写锁。在mysql中,写锁是优先于读锁的!写锁和读锁优先级的问题是可以通过参数调节的:max_write_lock_count和low-priority-updates
表锁下又分为两种模式: 表读锁(Table Read Lock)&& 表写锁(Table Write Lock),在表读锁和表写锁的环境下:读读不阻塞,读写阻塞,写写阻塞! 读读不阻塞:当前用户在读数据,其他的用户也在读数据,不会加锁 读写阻塞:当前用户在读数据,其他的用户不能修改当前用户读的数据,会加锁! 写写阻塞:当前用户在修改数据,其他的用户不能修改当前用户正在修改的数据,会加锁!
读锁和写锁是互斥的,读写操作是串行。
MVCC MVCC(Multi-Version ConcurrencyControl)多版本并发控制,可以简单地认为:MVCC就是行级锁的一个变种(升级版)。在表锁中我们读写是阻塞的,基于提升并发性能的考虑,MVCC一般读写是不阻塞的(很多情况下避免了加锁的操作)。 可以简单的理解为:对数据库的任何修改的提交都不会直接覆盖之前的数据,而是产生一个新的版本与老版本共存,使得读取时可以完全不加锁。 事务的隔离级别 事务的隔离级别就是通过锁的机制来实现,锁的应用最终导致不同事务的隔离级别,只不过隐藏了加锁细节,事务的隔离级别有4种:
Read uncommitted:会出现脏读,不可重复读,幻读
Read committed:会出现不可重复读,幻读
Repeatable read:会出现幻读(Mysql默认的隔离级别,但是Repeatable read配合gap锁不会出现幻读!)
Serializable:串行,避免以上的情况
作者:阿亮
链接:https://zhuanlan.zhihu.com/p/116866170
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
事务是数据库中的一个核心概念,指的是对数据库的一组操作作为一个整体,要么都执行要么都不执行。 事务有四大特性:
1. 原子性:每个事务都是一个整体,不可再拆分,事务中的sql语句要么都执行成功,要么都执行失败。
2. 一致性:事务执行前后数据库的状态保持一致。比如不管如何转账,转账前后的总钱数是不变的。
3. 隔离性:事务和事务之间不应该相互影响,保持隔离。
4. 持久性:事务一旦提交对数据库的修改就是永久的,即使电脑发生故障也不会影响该修改,因为他的结果是记录在存储设备上的。
事务中有一个重要的特性“事务的隔离性”指的是事务和事务之间不应该相互影响,保持隔离,然而在现实中多个事务可能会操作同一个数据,造成并发问题:
1.脏读:一个事务读取到了另一个事务尚未提交的数据。
2.不可重复读:事务一读取到了age的值20,事务二将该值修改成了28,事务一再次读取age的值28,事务一两次读取的age值不一致。
3.幻读:事务一读取到A表中有一条记录,事务二往A表中插入一条记录,事务一再次读取的时候记录变成了两条,就像发生幻觉一样。
不可重复读和幻读很相似,可以从两个角度理解两者的差别:
1.不可重复读是另一个事务修改了数据,导致该事务多次读取出来的值不一样,而幻读是另一个事务插入或删除了记录,导致该事务多次读取出来的记录数不一样
2.不可重复读的解决只需要锁住会发生修改的记录就可以,幻读需要锁住更大的范围。
正是因为有这些问题存在,数据库设置了隔离级别来处理:
1.读未提交(read uncommitted): 事务中的修改,即使没有提交,其他事务也可以看得到 在这种隔离级别下有可能发生脏读,不可重复读和幻读。 一家酒店对外预定房间,现在还剩四间房,一个顾客到小王这里来预定四间房,小王查询系统发现还剩四间就将这四间房预定出去,该事务还没提交的时候另一个顾客到小李这里来预定房间,小李查询系统发现没房了,就拒绝了这个订单,此时小王的电脑发生故障,事务回滚,订单失效,这就是脏读造成的影响。
2.读已提交(read committed): 事务中的修改只有提交以后才能被其它事务看到。在这种隔离级别下有可能发生不可重复读和幻读。 还是定房间的例子,一个顾客到小王这里来预定四间房,小王将这四间房预定了出去,该事务还没提交的时候另一个顾客到小李这里来预定房间,小李查询系统发现还有四间房,刚想预定的时候小王的事务提交了,小李的系统立马呈现0间房。这就是不可重复读造成的影响。
3.可重复读 (repeatable read):该级别保证了在事务中看到的每行的记录的结果是一致的,但是这种级别下有可能发生幻读。默认是可重复读 公司规定如果销售额达不到就要扣工资,经理查询小王的销售业绩,发现还差几间房,经理喜上眉梢,把结果打印出来,结果打印出来的结果业绩正好合格,原来小王在这当口又卖了几张票正好填上了这个空缺。这就是幻读造成的影响。
4.串行化(serializable):该级别下所有的事务都是串行执行的,一个事务执行完了才能执行其它的事务,可以解决所有的并发问题,它是靠大量加锁实现的,所以效率很低下。只有在需要绝对保证数据一致性,并且并发量不大的情况下,可以考虑。Read uncommitted: 出现的现象—>脏读:一个事务读取到另外一个事务未提交的数据,例子:A向B转账,A执行了转账语句,但A还没有提交事务,B读取数据,发现自己账户钱变多了!B跟A说,我已经收到钱了。A回滚事务【rollback】,等B再查看账户的钱时,发现钱并没有多… Read committed: 出现的现象—>不可重复读:一个事务读取到另外一个事务已经提交的数据,也就是说一个事务可以看到其他事务所做的修改,例如:A查询数据库得到数据,B去修改数据库的数据,导致A多次查询数据库的结果都不一样【危害:A每次查询的结果都是受B的影响的,那么A查询出来的信息就没有意思了】 Repeatable read: 避免不可重复读是事务级别的快照!每次读取的都是当前事务的版本,即使被修改了,也只会读取当前事务版本的数据
至于虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。和不可重复读类似,但虚读(幻读)会读到其他事务的插入的数据,导致前后读取不 一致,幻读的重点在于新增或者删除(数据条数变化),不可重复读的重点是修改,幻读和不可重复的区别?
悲观锁 我们使用悲观锁的话其实很简单(手动加行锁就行了):select * from xxxx for update,在select 语句后边加了for update相当于加了排它锁(写锁),加了写锁以后,其他事务就不能对它修改了!需要等待当前事务修改完之后才可以修改。
乐观锁 乐观锁不是数据库层面上的锁,需要用户手动去加的锁。一般我们在数据库表中添加一个版本字段version来实现,在更新User表的时,执行语句如下: update A set Name=lisi,version=version+1 where ID=#{id} and version=#{version}, 此时即可避免更新丢失。
举例:下单操作包括3步骤:
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};
除了自己手动实现乐观锁之外,现在网上许多框架已经封装好了乐观锁的实现,如hibernate,需要时,可能自行搜索"hiberate 乐观锁"试试看。
间隙锁GAP 当我们用范围条件检索数据而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合范围条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在 的记录,叫做“间隙(GAP)”。InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。例子:假如emp表中只有101条记录,其empid的值分别是1,2,…,100,101 Select * from emp where empid > 100 for update; 上面是一个范围查询,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁
InnoDB使用间隙锁的目的有2个:
为了防止幻读(上面也说了,Repeatable read隔离级别下再通过GAP锁即可避免了幻读)
满足恢复和复制的需要:MySQL的恢复机制要求在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读
死锁 并发的问题就少不了死锁,在MySQL中同样会存在死锁的问题 锁总结 表锁其实我们程序员是很少关心它的:
在MyISAM存储引擎中,当执行SQL语句的时候是自动加的。
在InnoDB存储引擎中,如果没有使用索引,表锁也是自动加的。
现在我们大多数使用MySQL都是使用InnoDB,InnoDB支持行锁:
共享锁–读锁–S锁
排它锁–写锁–X锁
在默认的情况下,select是不加任何行锁的~事务可以通过以下语句显示给记录集加共享锁或排他锁。
共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE
InnoDB基于行锁还实现了MVCC多版本并发控制,MVCC在隔离级别下的Read committed和Repeatable read下工作。MVCC实现了读写不阻塞
19. mysql主键索引和普通索引之间的区别是什么
1.普通索引(INDEX);
2.唯一索引(UNIQUE INDEX);
3.全文索引(FULLTEXT)(全文索引是MyISAM的一个特殊索引类型,主要用于全文检索);
4.单列索引、多列索引;
5.组合索引(最左前缀)。
普通索引
普通索引是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
创建索引,例如
CREATE INDEX<索引的名字>ON tablename (列的列表);
修改表,例如
ALTER TABLE tablename ADD INDEX[索引的名字] (列的列表);
创建表的时候指定索引,例如
CREATE TABLE tablename ( […],INDEX[索引的名字] (列的列表) );
主键索引
主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。
主键一般在创建表的时候指定,例如
CREATE TABLE tablename ( […],PRIMARYKEY(列的列表) );
但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。
区别
普通索引是最基本的索引类型,没有任何限制,值可以为空,仅加速查询。普通索引是可以重复的,一个表中可以有多个普通索引。
主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值;索引列的所有值都只能出现一次,即必须唯一。简单来说:主键索引是加速查询 + 列值唯一(不可以有null)+ 表中只有一个。
2.唯一索引和主键索引区别
答:1)主键为一种约束,唯一索引为一种索引,本质上就不同;
2)主键创建后一定包含唯一性索引,而唯一索引不一定就是主键;
3)主键不允许空值,唯一索引可以为空;
4)主键可以被其他表引用,而唯一索引不可以;
5)主键只允许一个,唯一索引允许多个;
6)主键和索引都是键,主键是逻辑键,索引为物理键,即主键不实际存在。
3.索引失效
答:1)最佳左前缀原则(组合索引,不按索引定义时制定的顺序,最左优先);
2)like模糊查询时,以%开头,导致索引失效;
3)使用“!=”和“<>”都会使索引失效,如果是主键或者索引列是整数,索引不会失效;
4)遇到null值,索引失效;
5)索引列上的显式或者隐式运算,导致索引失效;
6)如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引(如select * from USER where name=123;);
7)用or连接导致索引失效(or条件有未建立索引的列导致索引失效)。
4.索引的坏处
答:1)创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加;
2)索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大;
3)当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。
5.索引的方法
答:主要有以下几种索引方法:B-Tree,Hash,R-Tree。
20. SQL JOIN 中 on 与 where 的区别
left join : 左连接,返回左表中所有的记录以及右表中连接字段相等的记录。
right join : 右连接,返回右表中所有的记录以及左表中连接字段相等的记录。
inner join : 内连接,又叫等值连接,只返回两个表中连接字段相等的行。
full join : 外连接,返回两个表中的行:left join + right join。
cross join : 结果是笛卡尔积,就是第一个表的行数乘以第二个表的行数。
关键字 on
数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。
在使用 left jion 时,on 和 where 条件的区别如下:
1、 on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录。
2、where 条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有 left join 的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。
21. 优化 MYSQL 数据库的方法
1、对查询进行优化,应尽可能避免全表扫描
1)减少where 字段值null判断
2)应尽量避免在 where 子句中使用!=或<>操作符
3)应尽量避免在 where 子句中使用 or 来连接条件
4)in 和 not in 也要慎用
5)少使用模糊匹配 like
6)应尽量避免在 where 子句中对字段进行表达式操作
7)任何地方都不要使用*通配符去查询所有
2、不要在条件判断时进行 算数运算
3、很多时候用 exists 代替 in 是一个好的选择
4、 选取最适用的字段属性,尽可能减少定义字段长度,尽量把字段设置 NOT NULL, 例如’省份,性别’, 最好设置为 ENUM
5、SQL语句中IN包含的值不应过多
6、SELECT语句务必指明字段名称
SELECT *增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前断也需要更新。所以要求直接在select后面接上字段名。
7、当只需要一条数据的时候,使用limit 1
这是为了使EXPLAIN中type列达到const类型
8、如果排序字段没有用到索引,就尽量少排序
9、如果限制条件中其他字段没有索引,尽量少用or
10、尽量用union all代替union
11、区分in和exists, not in和not exists
12、使用合理的分页方式以提高分页的效率
13、分段查询
14、避免在 where 子句中对字段进行 null 值判断
15、不建议使用%前缀模糊查询
例如LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。
16、避免在where子句中对字段进行表达式操作
17、对于联合索引来说,要遵守最左前缀法则
22. 适用MySQL 5.0以上版本
一个汉字占多少长度与编码有关:
UTF-8:一个汉字=3个字节
GBK:一个汉字=2个字节
23. 什么时候适合创建索引
1、适合创建索引条件
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该建立索引
- 查询中与其他表关联的字段,外键关系建立索引
- 单键/组合索引的选择问题,组合索引性价比更高
- 查询中排序的字段,排序字段若通过索引去访问将大大提高排序效率
- 查询中统计或者分组字段
2、不适合创建索引条件
- 表记录少的
- 经常增删改的表或者字段
- where条件里用不到的字段不创建索引
- 过滤性不好的不适合建索引
3、在Mysql中ENUM的用法是什么?
ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用。
Create table size(name ENUM('Smail,‘Medium’,‘Large’);