zoukankan      html  css  js  c++  java
  • MySQL命令速记

    系统参数系列

    show table status where name = "film": 显示某个表的属性

    show status : 显示mysql状态

    show processlist : 显示mysql连接状态

    show index from user : 显示user表索引

    show profiles : 显示查询执行时间状况,使用前先设置参数 set profiling=1;

    show profile for query 1: 查看第一条sql的具体执行情况

     

    PAGER cat > /dev/null : 将输出转到垃圾黑洞

     

    TRUNCATE TABLE: 清空table所有数据并重置自增主键的值

     

    SELECT * INTO OUTFILE 'out.txt' FROM user : 将user表的数据选择出来以后导入到out.txt文件.

     

    Explain: 解析SQL语句的执行计划

    EXPLAIN SELECT * FROM USER\G;

    \G 表示输出EXPLAIN树 

     

    AUTOCOMMIT变量

    AUTOCOMMIT变量表示是否自动提交事务,MySQL中的每一条单独的查询都是一个单独的事务

    默认是AUTOCOMMIT=1时,如下是等价的

    UPDATE user SET age = 10 WHERE user_id = 1;

      与

    BEGIN;
    UPDATE user SET age = 10 WHERE user_id = 1;
    COMMIT;

      而如果SET AUTOCOMMIT=0,则我们执行的任何一条SQL都相当于在一个未提交的事务中,我们需要手动执行COMMIT或者说ROLLBACK.

     

    JOIN 系列

    MySQL中 cross join, join, inner join或者不加join都是等效的,如下

    SELECT * FROM USER,BOOK;

    SELECT * FROM USER CROSS JOIN BOOK;

    SELECT * FROM USER JOIN BOOK;

    SELECT * FROM USER INNER JOIN BOOK;

    另外,有JOIN里的ON和不加JOIN的WHERE等效如下:

    SELECT * FROM USER JOIN BOOK ON USER.USERID = BOOK.USERID;

    SELECT * FROM USER,BOOK WHERE USER.USERID = BOOK.USERID;

    SELECT * FROM USER,BOOK WHERE USING(USERID);

     

    LEFT JOIN, RIGHT JOIN

    SELECT * FROM USER LEFT JOIN BOOK ON USER.USERID = BOOK.USERID;

    等效于

    SELECT * FROM BOOK RIGHT JOIN USER ON BOOK.USERID = USER.USERID;

    这两句的意思是将左表的每条记录与右表中的每条记录相连,如果右表中存在的则显示出来,不存在的用NULL表示,如下图

     

    CREATE 系列

    create database student character set = utf8 collate = utf8_general_ci;
    
    create table student (
        stu_id int primary key not null auto_increment comment "主键id",
        stu_name varchar(5) comment "名称",
        stu_gender enum("男", "女") comment "性别",
        stu_dob date comment "出生年月",
        stu_natplace varchar(5) comment "籍贯",
        stu_depa varchar(5) comment "系",
        stu_intro blob comment "简介",
        stu_photo blob comment "照片",
        index stu_inx using btree (stu_name, stu_depa)
    ) engine = myisam,
      character set utf8,
      collate utf8_general_ci,
      comment = "学生信息表";
    
    create table score (
        stu_id int not null comment "学生id",
        cs_id int not null comment "课程id",
        score float not null comment "成绩",
        index stu_course_inx using btree (stu_id, cs_id)
    ) engine = myisam,
      character set utf8,
      collate utf8_general_ci,
      comment = "成绩表";
    
    create table course (
        cs_id int primary key not null auto_increment comment "主键id",
        cs_no char(8) not null unique comment "课程号",
        cs_credit float not null comment "学分",
        cs_hours tinyint not null comment "学时",
        cs_avg_grade float comment "平均分",
        cs_total_grade float comment "总分",
        index cs_no_inx using btree (cs_no)
    ) engine = myisam,
      character set utf8,
      collate utf8_general_ci,
      comment = "课程表";

    建表是,key和index是同义词,都是索引的的意思 

     LIMIT的使用

    mysql> SELECT * FROM table LIMIT 5,10;  // 检索记录行 6-15
    
    //为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1: 
    mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.
    
    //如果只给定一个参数,它表示返回最大的记录行数目: 
    mysql> SELECT * FROM table LIMIT 5;     //检索前 5 个记录行
    
    //换句话说,LIMIT n 等价于 LIMIT 0,n。

    UNION: 合并两个结果集并过滤掉重复内容

    UNION ALL: 合并两个结果集,结果集可能有重复

    使用UNION要注意的是两个结果集的SELECT项必须是相同的

    (select actor_id from actor) 
    union
    (select actor_id from film_actor)
    
    (select actor_id from actor) 
    union all 
    (select actor_id from film_actor)

     

    ALTER系列

    修改表名: ALTER TABLE USER RENAME TO USERTEMP;

    添加列: ALTER TALBE USER ADD COLUMN AGE INT;

    删除列: ALTER TABLE USER DROP COLUMN AGE;

    修改列: ALTER TABLE USER CHANGE AGE BIRTH INT;

    修改列属性: ALTER TABLE USER MODIFY AGE TINYINT;

    添加主键: ALTER TABLE USER ADD PRIMARY KEY(USERID);

    添加唯一索引: ALTER TABLE USER ADD UNIQUE (USERID);

    添加单列索引或联合索引(BTree索引): ALTER TABLE USER ADD INDEX index_name (column1, column2, column3);

    添加全文索引:ALTER TABLE USER ADD FULLTEXT (column) ; #仅限于MyISAM

    删除索引: ALTER TABLE USER DROP INDEX index_name;

    添加外键: ALTER TABLE USER ADD CONSTRAINT (CONSTRAINT_NAME) FOREIGN KEY (BOOKID) REFERENCES BOOK(BOOKID) ON UPDATE/DELETE RESTRICT/CASCADE;

    此处注意 ON UPDATE/DELETE RESTRICT/CASCADE;

    如果是 update restrict,则如果user表存在有bookid = n时,book表的这个bookid = n的行,不能更新bookid

    例如,user表存在 userid = 1, bookid = 2的行,就不能执行 update book set bookid = 3 where bookid = 2;

     

    如果是 update cascade,那么user表如果存在bookid = n, 当book表的bookid = n 这行被修改为bookid = x时,user表里的bookid = n 也会变为bookid = x

    例如,user表存在userid = 1, bookid = 2, 执行 update book set bookid = 3 where bookid = 2, 则user表里的 bookid = 2 都会变成 bookid = 3;

     

    如果是 delete restrict,那么如果user表里存在userid = 1, bookid = 2的行,就不能删除 book 表里bookid = 2的行

     

    如果是 delete cascade,那么如果 user 表里存在 userid = 1, bookid = 2的行, 此时如果删除book表里 bookid = 2 的行,则user表里所有bookid=2的行也会被删除

    删除外键: ALTER TABLE USER DROP FOREIGN KEY BOOKID;

     

     

    临时表

    当前数据库连接有效,数据库连接结束时自动drop

    当临时表名和已存在表名一样时,已存在表会被隐藏,直到临时表被drop

    临时表不能被重复打开,也即是说一条SQL查询不能出现两次临时表

    1.创建

    (1)CREATE TEMPORARY TABLE test_temp (id INT NOT NULL, age int);

    (2)CREATE TEMPORARY TABLE test_tem SELECT * FROM user;

    2.使用

    SELECT * FROM test_temp;

    3.删除

    DROP TABLE test_temp;

     

    日期函数

    1.获取时间: curtime() 输出:23:05:05

    2.获取日期: curdate() 输出:2012-10-09

    3.获取日期和时间: now(), sysdate() 输出 2012-10-09 23:05:05

    4.日期比较(不包括时间)函数: datediff("2010-10-10 20:10:11", now()) = 0 表示当前日期(不包括时间)等于 "2010-10-10"

    datediff的参数可以使datetime也可以是date,如果参数1小于参数2返回负数,相等返回0,否则返回整数,数值为天数的差值

    5.时间比较,直接用大于小于号

    6.返回日期的年份: SELECT YEAR('98-10-11'), 返回 1998

    7.UNIX_TIMESTAMP('2010-10-10 20:10:00'): 将日期时间转换成时间戳

     

    对于有联合索引(a, b)的表,如果执行以下查询

    SELECT a FROM tb1 WHERE b BETWEEN 2 AND 3

    即使b的范围很小,也需要进行全表扫描,因为没有用到前缀索引a,而Oracle则可以松散索引扫描达到高效查询

     

     

    使用LIMIT来提高MIN()的效率

    1. SELECT MIN(actor_id) FROM sakila.actor WHERE first_name = "PENELOPE";
    
    2. SELECT actor_id FROM sakila.actor WHERE first_name = "PENELOPE" LIMIT 1;

    此处由于first_name没有索引,所以会对actor表进行全表扫描,第一句SQL取出所有记录.而由于actor_id是主键,它的索引是按顺序排列的,使用limit取到的第一条记录肯定就是MIN的值,所以它的效率高,但是这样失去了SQL可以表达出来的查询意义,这是效率和原则之间的权衡.

     

    COUNT(expr): 统计所有expr不为null的行的行数,注意一下expr为假,并不代表为NULL,只有当expr确实返回NULL时,才是NULL

    COUNT(col): 统计col列的非NULL结果数

    COUNT(*): 统计结果集行数

    *对于MyISAM来说,COUNT(*)且没有任何WHERE条件是非常快的,因为它可以直接从存储引擎获得一个表的行数

    可以利用这点来优化COUNT查询,如下

    SELECT COUNT(*) FROM world.city WHERE id >5;

    这个语句需要扫描表中4000+行数据,而如果改成下面这种

    SELECT (SELECT COUNT(*) FROM world.city) - COUNT(*) FROM world.city WHERE id <= 5;

    这个语句仅仅扫描6条记录就可以得出结果,这是对于MyISAM而言,其他数据库引擎则不是这样

     

    CASE ... WHEN ... 与 IF

    统计不同颜色的商品数量

    SELECT SUM(IF(color='blue', 1, 0)) AS blue, SUM(IF(color='red', 1, 0)) AS red FROM items;
    
    SELECT SUM(CASE WHEN color='blue' THEN 1 ELSE 0 END) AS blue, SUM(CASE WHEN color='red' THEN 1 ELSE 0 END) AS red FROM items;

      也可以用COUNT()实现

    SELECT COUNT(color='blue' OR NULL) as blue, COUNT(color='red' OR NULL) as red FROM items

     GROUP BY 效率优化

    应该尽量使GOURP BY的COL拥有索引,这样可以降低临时表和filesort的使用

    select actor.first_name, actor.last_name, count(*)
        from film_actor 
        inner join actor USING(actor_id)
    group by actor.first_name, actor.last_name;

    explain分析

    1 SIMPLE actor ALL PRIMARY       200 Using temporary; Using filesort
    1 SIMPLE film_actor ref PRIMARY PRIMARY 2 sakila.actor.actor_id 13 Using index

    改为

    select actor.first_name, actor.last_name, count(*)
        from film_actor 
        inner join actor USING(actor_id)
    group by actor.actor_id;

    explain分析

    1 SIMPLE actor index PRIMARY,idx_actor_last_name PRIMARY 2   200  
    1 SIMPLE film_actor ref PRIMARY PRIMARY 2 sakila.actor.actor_id 13 Using index

    可见这两个查询的效率差异是很大的,前者使用了临时表和filesort做全表扫描,而后者只是做了一次索引覆盖扫描

    此外,GROUP BY默认会按照GROUP BY的列排序,如果不需要这个排序,可以ORDER BY NULL,或者使用DESC和ASC指定排序顺序

     

    GROUP_CONCAT 与 GROUP BY 的配合

    我们知道GROUP_BY(COL)会将COL列相同的值得行合在一起,这样就会损失其他列的数据

    如果要获取所有其他列的数据,则可以使用GROUP_CONCAT, 它可以将丢失的这些列值使用 ", " 拼接起来

    例如

    数据库数据

     

    直接使用group by,会损失一些password

     

    使用 group_concat 拼接 password

     

    LIMIT的优化

    考察下面的SQL语句,观察一下film表的index

    film 0 PRIMARY 1 film_id A 1000       BTREE    
    film 1 idx_title 1 title A 1000       BTREE    
    film 1 idx_fk_language_id 1 language_id A 2       BTREE    
    film 1 idx_fk_original_language_id 1 original_language_id A 2     YES BTREE    
    select film_id, description from film order by title limit 50, 5

      EXPLAIN结果

    1 SIMPLE film ALL         1000 Using filesort

    可知idx_title为辅助索引,由于innodb的辅助索引只记下了主键索引而没有其他内容,所以当我们同时查询film_id和desciption的时候,就无法使用title索引进行排序了,所以改成如下写法,做一个"延迟关联"

    select film_id, description from film 
    inner join (
        select film_id from film order by title limit 50, 5
    ) as tb using (film_id);

      EXPLAIN

    1 PRIMARY <derived2> ALL         55  
    1 PRIMARY film eq_ref PRIMARY PRIMARY 2 tb.film_id 1  
    2 DERIVED film index   idx_title 767   1000 Using index

    这种写法先产生子查询衍生表,查询的时候使用了title索引做索引覆盖扫描,然后再用外表与衍生表做联接,此时使用了主键索引,这种效率可以提高很多,对比如下

    44 0.00152075 select film_id, description from film order by title limit 50, 5
    48 0.00040575 select film_id, description from film inner join ( select film_id from film order by title limit 50, 5 ) as tb using (film_id)

      使用UNION与变量来做短路查询 

    select greatest(@found := -1, actor_id) as id, 'actor' from actor where actor_id = 1
        UNION ALL
    select actor_id, 'film_actor' from film_actor where actor_id = 1 and @found is null
        UNION ALL
    select 1, 'reset' from DUAL where (@found := null) is not null

    这个查询的效果是先查询actor表,当actor表查询得到记录时,@found变量会被赋值-1.这样第二个查询因为@found is null就不会被执行,最后再将@found重置为null

     

     

     

    FOR UPDATE 的替代方案

    如果使用SELECT ... FOR UPDATE会对记录加上行锁,在事务的后续操作过程中,可能会造成很多堵塞

    一个替代方案就是不用FOR UPDATE,而改用一个标志位来表示记录正在被处理,例如

    SET AUTOCOMMIT=1;
    COMMIT;
    UPDATE unsent_emails
        SET status='claimed', owner=CONNECTION_ID()
        WHERE owner=0 AND status='unsent'
        LIMIT 10;
    SET AUTOCOMMIT=0;
    SELECT id FROM unsent_emails
        WHERE owner=CONNECTION_ID() AND status='claimed';

    那么当前连接线程就可以在后续造作中没有顾虑的修改这些记录了,而不需要加锁,不会造成阻塞.

     

    LENGTH(), CHAR_LEGNTH(): 这两个函数用来计算字符串的长度,其中LENGTH()统计的字节数,CHAR_LEGNTH()是字符数

    例如 @name := '中国北京'  @name以UTF8编码

    LENGTH(@name) 是 12

    CHAR_LENGTH(@name) 是 4

     

     

    substring_index()的使用

    substring_index(str, delimiter, count) 可以从左开始计算delimiter在str中出现的次数,当出现次数达到count次时,如果count为正数,返回delimiter左边的字符串,如果count为负数,则返回delimiter右边的字符串,例子:

     

     

     

  • 相关阅读:
    bzoj 1503
    bzoj 1193 贪心+bfs
    bzoj 1798 线段树
    Codeforces 804D Expected diameter of a tree
    bzoj 1208
    bzoj 3224
    HDU 5115 区间dp
    hihocoder #1162 矩阵加速dp
    分块入门
    bzoj 1036 树链剖分
  • 原文地址:https://www.cnblogs.com/zemliu/p/2637134.html
Copyright © 2011-2022 走看看