最近在写项目的时候发现本身的SQL基本功有些薄弱,遂上知乎查询MYSQL关键字,指望获得某些高赞答案的指点,因而乎发现了html
https://www.zhihu.com/question/34840297/answer/272185020 这位老兄的建议的书单,根据他的建议首先拜读了《MYSQL必知必会》这本书,总体讲的很基础,页数也很少一共 253 页,适合基础比较薄弱的同窗进行食用。而后按部就班,阅读更深层次的书籍进行自我提高。这里记载了本身在阅读的过程当中记录的一些关键内容,分享给你们。书本 PDF 能够在上面的知乎连接获取,或者点击 http://www.notedeep.com/note/38/page/282 前往老哥的深度笔记进行下载。mysql
SQL语句不区分大小写,而且在 Windows 环境下,4.1.1版本以后(如今经常使用的都是 5.6/5.7/8.0+),MYSQL表名,字段名也是不区分大小写的,所以咱们在命名的时候建议使用单个单词_单个单词的形式命名,如:mysql_crash_course user_rolesql
这里附上阿里代码规范的一条强制要求:数据库
【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,由于没法进行预发布,因此字段名称须要慎重考虑。
说明: MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。所以,数据库名、表名、字段名,都不容许出现任何大写字母,避免节外生枝。服务器
好比项目中有这么一个需求:多线程
须要分页查询绑了某收费标准的房屋,由于是房屋列表查询,咱们默认相同ID的房屋只出现一次,错误的SQL以下:并发
房屋表app
收费标准表less
SELECT DISTINCT h.id, h.num, s.name FROM house h LEFT JOIN standard s ON h.id = s.room_id WHERE s.name = '物业费' OR s.name = '暖气费';
这条语句并不能返回想要的结果,即每套房屋只出现一次,由于不一样的收费标准名称不同,DISTINCT 不能对部分查询条件去重。能够看到房号为1-001的记录出现了两次。ide
不过其实按照需求的描述我这里仅查询房屋的信息,对于查询结果来讲同一条记录的房屋信息确定彻底相同,所以 DISTINCT 在个人业务中知足要求。而有其余业务须要此关键字的时候,请你们慎重使用,切记不能部分使用该关键字
在对文本性的数据进行排序时,A与a相同吗?a位于B以前仍是位于Z以后?
在建立字段时能够指定字符集,通常使用 utf8mb4, 此时能够选择相应的排序规则。
在区间查询时,咱们最关注的不该该是区间内的可否被匹配到,由于这是确定的。而区间的边界可否被匹配才是咱们应该注意的知识点,BETWEEN AND 关键字匹配区间时,包含左右边界条件。以下面的 SQL 执行结果以下:
SELECT prod_name, prod_price FROM products p WHERE p.`prod_price` BETWEEN 5.99 AND 10
在经过过滤选择出不具备特定值的行时,你可能但愿返回具备 NULL 值的行。可是,不行。常见的错误会发生在is_xxx 字段上,我常常有这个毛病,
对于 is_delete 字段,我认为为 null 或者 0 都是未删除的房屋,因此当我使用
SELECT * FROM house WHERE is_delete = '0';
查询未删除的房屋时,我只能查到 id 为 3 的房屋,这显然与个人预期是不符的,解决办法是where后面加 or is_delete is null ,或者给 is_delete 列默认值 0;建议使用后者。
这里附上阿里代码手册的一条强制项目:
【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint(1 表示是,0 表示否)。说明:任何字段若是为非负数,必须是 unsigned 。
解释:tinyint 至关于 Java 中的 byte,取值范围 -128 ~ 127 ,用来表达是否长度已经足够,也能够用来表示人的年龄。而 unsigned 表示无符号的,对于肯定为非负数的字段,使用 unsigned 能够将取值范围扩大一倍。
举个例子:假如须要列出价格为10美圆(含)以上且由 1002 或 1003 制造的全部产品。下面的 SELECT 语句使用 AND 和 OR 操做符的组合创建了一个WHERE 子句:
SELECT * FROM products WHERE vend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;
查询结果以下:
而被我用红框标注的行很显然不是咱们须要的行,为何会这样呢?缘由在于计算的次序。SQL(像多数语言同样)在处理 OR 操做符前,优先处理 AND 操做符。当SQL看到上述 WHERE 子句时,它理解为由供应商 1003 制造的任何价格为10美圆(含)以上的产品,或者由供应商 1002 制造的任何产品,而无论其价格如何。换句话说,因为 AND 在计算次序中优先级更高,操做符被错误地组合了。解决方法就是加 ();正确的 SQL 以下:
SELECT * FROM products WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;
建议在任什么时候候使用具备 AND 和 OR 操做符的 WHERE 子句,都应该使用圆括号明确地分组操做符。不要过度依赖默认计算次序,即便它确实是你想要的东西也是如此。使用圆括号没有什么坏处,它能消除歧义。
通常不要使用没有明确给出列的列表的 INSERT 语句。使用列的列表能使SQL代码继续发挥做用,即便表结构发生了变化。实际开发中有可能因为业务的须要,对表结构进行修改,添加/删除某一列。这时若是代码中使用的SQL语句是没有明确列表的插入语句就会报错。固然通常咱们使用逆向工程生成的 insertSelective(POJO) 并不存在这个问题,由于它对应生成的 SQL 会为咱们生成列的列表。
MySQL 没有撤销按钮,所以在使用 UPDATE / DELETE 时必定要加上 WHERE 条件,而且在执行更新/删除操做以前先进行 SELECT 操做,开启事务。在执行结束后核对影响的行数和 SELECT 查询出来的行数一致后再 COMMIT;
另外,使用 ALTER TABLE 要极为当心,应该在进行改动前作一个完整的备份(模式和数据的备份)。数据库表的更改不能撤销,若是增长了不须要的列,可能不能删除它们。相似地,若是删除了不该该删除的列,可能会丢失该列中的全部数据。
其中视图不能索引这一点要格外注意,在我开发过程当中遇到过这样一个视图:使用 UNION 连结了好几张表进行查询,对查询的结果使用 WHERE 条件再过滤,这里虽然对于被链接的表对于 WHERE 条件后的字段都创建了索引,可是使用 UNION 连结生成视图的临时表并不能拥有索引。所以查询的效率会很慢!因此建议在 UNION 查询中将 WHERE 条件放在每一个 SELECT 语句中。
首先,MySQL(与全部DBMS同样)具备特定的硬件建议。在学习和研究MySQL时,使用任何旧的计算机做为服务器均可以。但
对用于生产的服务器来讲,应该坚持遵循这些硬件建议。
通常来讲,关键的生产DBMS应该运行在本身的专用服务器上。
MySQL是用一系列的默认设置预先配置的,从这些设置开始一般是很好的。但过一段时间后你可能须要调整内存分配、缓冲区大小等。(为查看当前设置,可以使用 SHOW VARIABLES; 和 SHOWSTATUS; )
MySQL一个多用户多线程的DBMS,换言之,它常常同时执行多个任务。若是这些任务中的某一个执行缓慢,则全部请求都会执
行缓慢。若是你遇到显著的性能不良,可以使用 SHOW PROCESSLIST显示全部活动进程(以及它们的线程ID和执行时间)。你还能够用KILL 命令终结某个特定的进程(使用这个命令须要做为管理员登陆)。
老是有不止一种方法编写同一条 SELECT 语句。应该试验联结、并、子查询等,找出最佳的方法。
使用 EXPLAIN 语句让MySQL解释它将如何执行一条 SELECT 语句。
通常来讲,存储过程执行得比一条一条地执行其中的各条MySQL语句快。但存储过程通常难以调试和扩展,而且没有移植性,所以阿里代码规约里面强制禁止使用存储过程
应该老是使用正确的数据类型。
决不要检索比需求还要多的数据。换言之,不要用 SELECT * (除非你真正须要每一个列)。
有的操做(包括 INSERT )支持一个可选的 DELAYED 关键字,若是使用它,将把控制当即返回给调用程序,而且一旦有可能就实际执行该操做。
延迟插入,当插入和查询并发执行时,插入被放入等待队列中。直至全部查询执行完毕后执行插入。而且MYSQL会在收到插入请求后直接返回给客户端状态信息,既是INSERT语句还在队列中
在导入数据时,应该关闭自动提交。你可能还想删除索引(包括FULLTEXT 索引),而后在导入完成后再重建它们。
必须索引数据库表以改善数据检索的性能。肯定索引什么不是一件微不足道的任务,须要分析使用的 SELECT 语句以找出重复的WHERE 和 ORDER BY 子句。若是一个简单的 WHERE 子句返回结果所花的时间太长,则能够判定其中使用的列(或几个列)就是须要索引的对象。
你的 SELECT 语句中有一系列复杂的 OR 条件吗?经过使用多条SELECT 语句和链接它们的 UNION 语句,你能看到极大的性能改进。
索引改善数据检索的性能,但损害数据插入、删除和更新的性能。若是你有一些表,它们收集数据且不常常被搜索,则在有必要以前不要索引它们。(索引可根据须要添加和删除。)
LIKE 很慢。通常来讲,最好是使用 FULLTEXT 而不是 LIKE 。可是 MYSQL FULLTEXT 对汉字并不友好,若是须要使用全文索引,建议使用搜索引擎 ES,能够参考个人另外一篇博客: https://www.cnblogs.com/keatsCoder/p/11341835.html
数据库是不断变化的实体。一组优化良好的表一下子后可能就面目全非了。因为表的使用和内容的更改,理想的优化和配置也会改变。
最重要的规则就是,每条规则在某些条件下都会被打破。
实际开发过程当中,咱们须要根据业务的须要,开启慢查询日志,而后针对慢SQL,不断地进行 EXPLAIN 与修改SQL和索引,以求达到 ref 级别,至少达到 range 级别。这就须要强大的内功支持而不是每次都经过百度来解决,但愿阅读此篇文章的你和我一块儿不断修炼。加油!
因为数中所附的附件内容(建表语句即数据插入语句)须要外网才能访问,为了方便你们使用。这里我已经下载下来附在了这篇博客里面。若是不须要这些语句,能够直接经过网页右边的目录跳跃到下一章进行浏览
######################################## # MySQL Crash Course MYSQL必知必会建表语句 # http://www.forta.com/books/0672327120/ # 提供者博客园:后青春期的Keats 复制请注明出处 ######################################## ######################## # Create customers table ######################## CREATE TABLE customers ( cust_id int NOT NULL AUTO_INCREMENT, cust_name char(50) NOT NULL , cust_address char(50) NULL , cust_city char(50) NULL , cust_state char(5) NULL , cust_zip char(10) NULL , cust_country char(50) NULL , cust_contact char(50) NULL , cust_email char(255) NULL , PRIMARY KEY (cust_id) ) ENGINE=InnoDB; ######################### # Create orderitems table ######################### CREATE TABLE orderitems ( order_num int NOT NULL , order_item int NOT NULL , prod_id char(10) NOT NULL , quantity int NOT NULL , item_price decimal(8,2) NOT NULL , PRIMARY KEY (order_num, order_item) ) ENGINE=InnoDB; ##################### # Create orders table ##################### CREATE TABLE orders ( order_num int NOT NULL AUTO_INCREMENT, order_date datetime NOT NULL , cust_id int NOT NULL , PRIMARY KEY (order_num) ) ENGINE=InnoDB; ####################### # Create products table ####################### CREATE TABLE products ( prod_id char(10) NOT NULL, vend_id int NOT NULL , prod_name char(255) NOT NULL , prod_price decimal(8,2) NOT NULL , prod_desc text NULL , PRIMARY KEY(prod_id) ) ENGINE=InnoDB; ###################### # Create vendors table ###################### CREATE TABLE vendors ( vend_id int NOT NULL AUTO_INCREMENT, vend_name char(50) NOT NULL , vend_address char(50) NULL , vend_city char(50) NULL , vend_state char(5) NULL , vend_zip char(10) NULL , vend_country char(50) NULL , PRIMARY KEY (vend_id) ) ENGINE=InnoDB; ########################### # Create productnotes table ########################### CREATE TABLE productnotes ( note_id int NOT NULL AUTO_INCREMENT, prod_id char(10) NOT NULL, note_date datetime NOT NULL, note_text text NULL , PRIMARY KEY(note_id), FULLTEXT(note_text) ) ENGINE=MyISAM; ##################### # Define foreign keys ##################### ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num); ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id) REFERENCES products (prod_id); ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id); ALTER TABLE products ADD CONSTRAINT fk_products_vendors FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);
######################################## # MySQL Crash Course MYSQL必知必会数据语句 # http://www.forta.com/books/0672327120/ # 提供者博客园:后青春期的Keats 复制请注明出处 ######################################## ########################## # Populate customers table ########################## INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd'); ######################## # Populate vendors table ######################## INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1001,'Anvils R Us','123 Main Street','Southfield','MI','48075', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1002,'LT Supplies','500 Park Street','Anytown','OH','44333', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1003,'ACME','555 High Street','Los Angeles','CA','90046', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1004,'Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1005,'Jet Set','42 Galaxy Road','London', NULL,'N16 6PS', 'England'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1006,'Jouets Et Ours','1 Rue Amusement','Paris', NULL,'45678', 'France'); ######################### # Populate products table ######################### INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV01', 1001, '.5 ton anvil', 5.99, '.5 ton anvil, black, complete with handy hook'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV02', 1001, '1 ton anvil', 9.99, '1 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV03', 1001, '2 ton anvil', 14.99, '2 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('OL1', 1002, 'Oil can', 8.99, 'Oil can, red'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FU1', 1002, 'Fuses', 3.42, '1 dozen, extra long'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SLING', 1003, 'Sling', 4.49, 'Sling, one size fits all'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT1', 1003, 'TNT (1 stick)', 2.50, 'TNT, red, single stick'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT2', 1003, 'TNT (5 sticks)', 10, 'TNT, red, pack of 10 sticks'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FB', 1003, 'Bird seed', 10, 'Large bag (suitable for road runners)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FC', 1003, 'Carrots', 2.50, 'Carrots (rabbit hunting season only)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SAFE', 1003, 'Safe', 50, 'Safe with combination lock'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('DTNTR', 1003, 'Detonator', 13, 'Detonator (plunger powered), fuses not included'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP1000', 1005, 'JetPack 1000', 35, 'JetPack 1000, intended for single use'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP2000', 1005, 'JetPack 2000', 55, 'JetPack 2000, multi-use'); ####################### # Populate orders table ####################### INSERT INTO orders(order_num, order_date, cust_id) VALUES(20005, '2005-09-01', 10001); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20006, '2005-09-12', 10003); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20007, '2005-09-30', 10004); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20008, '2005-10-03', 10005); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20009, '2005-10-08', 10001); ########################### # Populate orderitems table ########################### INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 1, 'ANV01', 10, 5.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 2, 'ANV02', 3, 9.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 3, 'TNT2', 5, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 4, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20006, 1, 'JP2000', 1, 55); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20007, 1, 'TNT2', 100, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20008, 1, 'FC', 50, 2.50); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 1, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 2, 'OL1', 1, 8.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 3, 'SLING', 1, 4.49); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 4, 'ANV03', 1, 14.99); ############################# # Populate productnotes table ############################# INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(101, 'TNT2', '2005-08-17', 'Customer complaint: Sticks not individually wrapped, too easy to mistakenly detonate all at once. Recommend individual wrapping.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(102, 'OL1', '2005-08-18', 'Can shipped full, refills not available. Need to order new can if refill needed.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(103, 'SAFE', '2005-08-18', 'Safe is combination locked, combination not provided with safe. This is rarely a problem as safes are typically blown up or dropped by customers.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(104, 'FC', '2005-08-19', 'Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(105, 'TNT2', '2005-08-20', 'Included fuses are short and have been known to detonate too quickly for some customers. Longer fuses are available (item FU1) and should be recommended.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(106, 'TNT2', '2005-08-22', 'Matches not included, recommend purchase of matches or detonator (item DTNTR).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(107, 'SAFE', '2005-08-23', 'Please note that no returns will be accepted if safe opened using explosives.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(108, 'ANV01', '2005-08-25', 'Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(109, 'ANV03', '2005-09-01', 'Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(110, 'FC', '2005-09-01', 'Customer complaint: rabbit has been able to detect trap, food apparently less effective now.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(111, 'SLING', '2005-09-02', 'Shipped unassembled, requires common tools (including oversized hammer).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(112, 'SAFE', '2005-09-02', 'Customer complaint: Circular hole in safe floor can apparently be easily cut with handsaw.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(113, 'ANV01', '2005-09-05', 'Customer complaint: Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(114, 'SAFE', '2005-09-07', 'Call from individual trapped in safe plummeting to the ground, suggests an escape hatch be added. Comment forwarded to vendor.' );