order by返回的式游标而不是集合。唯一能重用列别名一步:语法顺序,执行顺序:(8)select (9)distinct (1) from【left_table】(3)
使用order by后面接数字的方式来进行排序:select 姓名 as name,地址 as address,城市 as city from customers order by 1,2,3。第1,第2,第3个字段(也就是name,address,city)。请慎用order by加数字,尽量使用order by加列明或列别名。
表表达式式不能使用order by排序,表表达式包括视图,内联表值函数,派生表(子查询)和公用表表达式(CTE)。因为视图,内联表值函数,派生表(子查询)和公用表表达式(CTE)等返回的结果还需要进一步的去使用,加了order by进行排序是多此一举,反而会浪费系统资源。所以数据库的开发者不希望大家使用这样不规范的操作。
T-SQL(transact-sql是结构话查询语言的(sql)的增强版本)中表表达式加了top,offset或for xml可以使用order by的限制。因为带有order by的表表达式加了top后返回的是一个没有笃定顺序的表。子查询中不能使用order by的限制。
count 1.不要使用count(1)或者count(*),要使用select 1 … limit 1.分页,1 id限定优化:id between … and … 2 使用临时表优化:使用临时存储的表来记录分页的id,使用分页的id。
命令:看执行时间:set profiling=1;show profiles;show profile(for query 2);show profile all/cpu。查看连接:show processlist。
performance库(87张表),show variables like ‘performance_schema’。
更小的更好,尽量用少的空间。简单就好,不同的数据格式,查询时间不同。ip用select inet_ATON(‘192.1.1.101’)和inet_NTOA(131351321).尽量避免null。
实际细则:整数类型:bigint(64)、tinyint(8)、int(32)、smalint(16)、mediumint(24)。字符和字符串类型:char:最大255,会自动删除末尾空格,效率比varchar高,存储密码,存储短字符串。varchar:存储长度波动很大的数据,存储字符串很少变更的场景,多字节字符。text。blob。datetime,占用八个字节,与时区无关,可以保存到毫秒,可保存的时间范围大,不要使用字符串存储时间,不仅占用空间还破坏函数便捷性。timestamp,占用四个字节,精确到秒,整形存储,依赖数据库设置的时区,1970-01-01–2039-01-19,自动更新列的值。date:3个字节,使用日期时间函数,1000-01-01—9999-01-19.自动更新列的值。date,3个字节,使用日期函数,1000-01-01—9999-12-31.用枚举类型代替字符串,create table enum_test (e enum(‘fish’,‘dog’)not null)。select e+0 from enum_test。
合理使用范式和反范式:范式:优点,更新比范式快。很少或者没有重复的数据。数据少,放在内存比较快。缺点:需要进行join。反范式:优点,避免关联。可以设计有效的索引。缺点,冗余多。三范式,列不可分,不能存在传递依赖,表的其他列必须唯一的以来主键。
主键的选择,代理主键,自然主键,推荐使用代理主键,不和业务耦合,因此更容易维护,通用的键策略能够减少源码数量,降低成本。
字符集的选择(utf8 mb4),纯拉丁字符尽量使用latin1,减少存储空间。不需要存放多种语言就没必要使用utf8和unicode。
存储引擎选择:InnoDB,数据和索引放在一起,B+树第三层存储的是实际的数据,聚簇,有覆盖索引。MyISAM,B+树第三层存储的是地址,多了一次IO,非聚簇,有覆盖索引。memory(用的hash散列),基于内存非常快,不能进行持久化。
适当的数据冗余,确保冗余字段被更新。
适当拆分,把不用的字段放到另外的表中。
执行顺序,相同的从上往下,不同的越大越先执行。
属性值,select_type,type,类型,以何种方式访问数据,system-》const-》ref-》rang-》index-》all。id。table。possible_keys。key。key_len,越小越好。ref,显示索引那一列引用了,是一个常数,const表示常量值。rows预估值。extra,出现并不太好,using filesort、using where、using index(索引覆盖)、using index condition。
底层存储用的B+树。链表节点树为8,总体为64会转为红黑树。红黑树是在AVL树的基础上牺牲了一部分查询效率级高了查询效率。一个索引就是一个树。磁盘预读,16k=4页。索引的优点,大大减少数据库需要扫描的数据量,帮助服务器避免排序和临时表,将随机io变为顺序io。索引的用处:1快速查找匹配where子句中的行 2 使用最少行的索引 3 左前缀查找行 4 当有表连接的时候,从其他表检索行数据 5 查找特定索引列的min和max的值 6 如果排序或者分组时可用索引的最左前缀完成的,则对表进行排序和分组 7 可以优化查询以检索数据值而无需查找数据行。
索引的类型:主键索引,唯一索引,普通索引,全文索引,组合索引,默认建立的索引是给唯一键建立的。面试技术名词:回表,从name列的B+树找主键,再从主键的B+树找到最终的数据。覆盖索引,select id ,id的值在回表的第一步就已经有了,就不需要第二步了,,就叫覆盖索引。最左匹配。索引下推。采用的数据结构,哈希表,B+树。索引的匹配方式,全值匹配,最左前缀匹配,匹配列前缀,匹配范围值,精确匹配某一列,并范围匹配另一列,只访问索引的查询。哈希索引,只有精确匹配所有列的查询才有效,只有memory存储引擎才支持。只存储对应的hash值,hash冲突,扰动函数,减少hash冲突。CRC32,循环冗余校验算法。组合索引。聚簇索引与非聚簇索引(数据存放的方式),聚簇索引,数据行跟紧邻的键值紧凑的存储在一起,非聚簇索引,先关掉索引,导入数据,打开索引,,防止索引更新。覆盖索引,索引存在与具体的文件里面,idb既有索引又有数据,MYD数据,MYI索引。
优化细节:当使用索引列进行查询的时候,尽量不要使用表达式,应该把计算放到业务层。尽量使用主键查询,而不是其他索引,因为主键查询不会触发回表查询。使用前缀索引,alert table table1 add key(city(7))前缀索引 ,select count(distinct left(city,3))/count(1),count(distinct left(city,4))/count(1) from emp。cardinality ,count(distinct(a))去重之后胃一直,基数。hyperloglog。使用索引进行排序,a=order by b,c 要么都是asc,要么都是desc。a=order by a,b;1 如果where里面的条件和order by的条件能组成最左匹配的话就用索引排序,如果where里面是范围就不能用了。2 如果order by的顺序和组合索引不一样没办法进行排序。
union all(union还得去重),in(oracle有个数限制为10000),or都能进行排序,推荐使用in,and优先级比or高,exist比in快,但写起来麻烦。范围列可以用到索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列。<,>,<=,>=,between.强制类型转换会全表扫描,如果phone为varchar,使用select * from table where phone=112311111,不会触发索引。更新十分频繁,数据分区高度不高的字段上不宜建立索引,更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能,类似性别这类,不能有效过滤数据,一般区分度在80%以上就可以建立索引,区分度可以使用count(distinct(a))/count(1)。创建索引的列不允许为null,可能会得到不符合预期的结果。
join:当需要进行表连接的时候,最好不要超过三张表,因为需要join的字段数据类型必须一致。join…on…是为了区分连接字段和筛选字段。如果明确知道只有一条数据返回,可以使用limit 1提高效率。A constraint join B 强制先执行A在执行B。小表join大表。map join(小表先放内存对大表join)。join的方式,simple nested-loop join效率低,数据库开销大,index nested-loop join。block nested-loop join,join buffer大小256K,可以调,在mysql5.1.22之前是4G-1,之后在64位系统下可以设置为>4G,使用join buffer需要设置optimizer_switch的block nested-loop join为on,默认开启,show variables like “%optimizer_switch%”。大表join大表,使用分区表,筛选。
select * from t1 left join t2 on t1.id=t2.id;select * from t1 left join t2 on t1.id=t2.id and t1.name=‘张三’,on后面的一串条件,除了关联还要筛选name是‘张三’的,根据关联条件去t2表拿id与t1一样的,没有的话右侧全是null。使用相同的连接键。能使用limit的时候尽量使用limit。单表索引尽量控制在5个以内,索引数目多,对应的磁盘空间大,io量就会大。单索引字段锁不允许超过5以内(组合索引)。创建索引的时候应该避免以下错误概念,索引越多越好,越早优化,在不了解系统的情况下进行优化,应该是实际的优化步骤,不应该是一直说一大堆技巧。索引监控,参数,show status like ‘handler_read%’等。
表共享读锁,对一个表加读锁,那么除了这个表之外的其他的表也能访问,目的是为了防止死锁,因为假如用户a锁住A表想查询B表,用户B锁住B表想查看A表会出现死锁。表独占写锁。如果table_locks_waited比较高,则说明存在这比较严重的表级锁争用情况。
并发事务问题,脏读,不可重复度,幻读。如果锁争用比较严重,innodb_ROW_LOCK_WAITS和innodb_ROW_LOCK_TIME_AVG值会比较高。共享锁(读锁)log in share mode。排它锁(写锁)for update。意向共享锁。意向排它锁。自增锁,auto_increament自增列,表锁。间隙所。行锁针对索引加锁。如果where条件后面没有索引列,表示表锁,有的话就是行锁。mysql5.7之后引入了MTS,并行复制技术
general,sock,客户端和服务端进行配置的。connection,max_user_connections,0表示不限制。show variables like ‘%back_log%’,在连接满时,等待堆栈维持的请求数。wait_TIMEOUT,关闭非交互链接等待时长。interactive_timeout,关闭非交互链接等待时长。长连接等待时长默认一小时。
redo,前滚日志,innodb,循环写,空间会用完,随机写。undo,回滚日志,innodb。bin log(默认不开启),服务端日志,mysql server,所有的引擎都可以有的,追加,顺序写。二阶段提交,三阶段提交:二阶段提交:先看内存有没有没有的话直接返回,更新数据,引擎将数据写入内存,同时写入redo,此时处于prepare阶段,并通知执行器执行完成,随时可以操作,执行器生成binlog,执行事务提交接口,引擎把redo的状态改为commit,更新完成;没有的话读磁盘。A原子性C一致性I隔离性D持久性,C最重要;A通过undo实现,I通过锁,D通过redo实现。commit,通过redo log写到log buffer再写到os buffer最后调用fsync()写到磁盘。general_log,是否开启查询日志记录,默认关闭。general_log_file,指定查询日志文件名,用于记录所有的查询语句。show_query_log,show_query_log_file,long_query_time设置慢查询时间。log_show_admin_statements,是否将管理语句写入慢查询日志。ad_hoc即席查询。
key_buffer_SIZE,索引缓存区大小。shpw status like ‘%qcache%’,query_cache_size。query_cache_limit。query_cache_min_res_unit缓存块最小大小,默认为4K,应该为4K整数倍。query_cache_type,0表示禁用,1表示缓存,2表示只有加sql_cache才会缓存。
innodb_buffer_pool_size,最大可以是物理内存80%.innodb_flush_log_trx_commit,写入日志文件并flush磁盘的时间点,0,1,2.innodb_thread_currency,跟核心数一致,或者是核心数的两倍。httpd用的BIO,nginx用的nio。read_rnd_buffer_size,随机读的缓存区大小,索引。
查询慢的原因:网络,CPU,io,上下文切换,系统调用,生成统计信息,锁等待时间。优化数据库访问,查询性能低下的主要原因是访问的数据太多,某些查询不可避免的需要筛选大量的数据我们可以通过减少访问数据量的方式进行优化–IO,确定应用程序是否检索大量超过需要的数据,确认MySQL服务器层是否在分析大量超过需要的数据行,貌似是30%。是否向数据库请求了不需要的数据,查询不需要的记录,多表关联时返回全部列,严格避免*,表关联要加别名。总是取出全部列。重复查询相同的一些数据。查询缓存在mysql8就被干掉了,当库里的数据更新插入很频繁的时候(命中率比较低),意味着查询缓存会经常失效,其实缓存用redis更合适,如果内存满了,还要使用相应的淘汰策略(LRU)
执行过程优化,查询缓存。查询优化处理,语法解析器和预处理,AST tree(抽象语法树),calcite。查询优化器,RBU(基于规则的优化),CBU(基于成本的优化)。show status like ‘last_query_cost’最后一次查询所用的成本,结果是经历多少个数据页,基于:每个表或者索引的页面个数,索引的基数,索引和数据行的长度,索引的分布情况。在很多情况下,mysql通常会选择错误的执行计划,原因如下:1统计信息不正确2 执行计划的成本估算不等同于实际执行的脚本3mysql的最优可能跟你想的不一样4mysql不考虑其他并发的查询5 mysql不会考虑不受其控制的操作成本;优化器的优化策略:静态优化,直接对解析树进行优化并完成优化,动态优化,mysql对查询的静态优化只需要一次,但对动态优化每次执行前都需要重新评估。优化器的优化类型:重新定义关联表的顺序,将外连接转换为内连接,内连接效率高,因为内连接数据量少,使用等价变换规则,优化count,min,max;min和max的优化可以使用分组条件,因为分组可以使用索引,预估并转换为常数表达式,当mysql检测到一个表达式可以可以转换为一个常数的时候,就会把该表达式作为常数处理,例如:a>4 AND A<4可以转换为a!=4,索引覆盖,子查询优化,等值传播,谓词下推,先把数据过滤,再进行连接。关联查询,一般情况下,很少改优化器,select straight join a,b…从头读表。排序优化,一次传输数据,直接全取出来排序,当排序的列的总大小+order by列的大小超过max_length_for_sort_data,就用双次排序,反之。当然,用户可以自定义。
特定类型的优化,count,count(1),count(*),count(id)为null时不计算。优化关联条件,确保on或者using上有索引,创建索引时要考虑关联的顺序,确保orderby和group by只涉及到一个列。优化子查询,尽可能使用关联代替子查询。如果对关联查询做分组,并且是按照查询表中的某个列进行分组,那个可以采用查询表的标识列(关联字段)分组的效率比其他列高。
使用用户自定义变量,@p表示自定义变量,@@p表示系统变量;set@i:=1;selet @i;select @@autocommit,当前会话有效,开窗函数row_number over。current_date系统时间,优化排名语句,再给一个变量赋值的同时使用这个变量,变重复查询刚刚更新的数据,确定取值的顺序(执行顺序)。‘优化limit分页,id>XXX’,BETWEEN AND,INNER JOIN 使用覆盖索引。优化union,行转列(join,union,case when,DV,distinct value)。
应用场景:表很大以至于无法全部放入内存,或者只在标的最后部分有热点数据,其他都是历史数据,分区表的数据更容易维护,分区表的数据可以分布在不同的物理设备上,从而高效的利用多个物理设备,可以使用分区表避免某些特殊的瓶颈:ext3文件系统的inode锁竞争,innodb单个索引的互斥访问。可以备份和恢复独立的分区。
分区表的限制:一个表只能有1024个分区,在5.7的时候可以支持8196个分区,1G内存10万个文件,限制65535,5.5的mysql可以直接使用列进行分区,如果分区字段中主键或者唯一索引的列,那么所有的主键和唯一索引列都必须包含进来,分区表无法使用外键约束,因为数据文件在不同的设备上。
分区表的磁盘底层原理:分区表由多个相关的底层表实现,底层表也是有句柄对象表示。
分区表的类型:列分区,低版本int,高版本没有限制;hash分区;key分区;子分区;范围分区。
如何使用分区表:全量扫描数据,不要任何索引。索引数据,并分离索引。