目前阿里云推出的 云数据库RDS 的版本有
5.7
、5.6
、5.5
三个版本,以下测试是基于5.7
版本。全文也会随着版本流行度进行及时更新,原文更新地址:https://github.com/about-cloud/JavaCore
EXPLAIN
是用来查询 SQL 的执行计划,
用法:
EXPLAIN SELECT [字段...] FROM TABLE;
结果:
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | t0 | NULL | range | idx_trade_id | idx_trade_id | 8 | NULL | 2 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+
1 row in set (0.02 sec)
重要字段说明:
select_type:使用的SELECT查询类型,比如SIMPLE、PRIMARY、UNION、SUBQUERY等;
table:关于访问哪张表,如果是多表,则按访问的先后顺序排列;
type:非常非常重要的指标,表示MySQL在表中找到行记录的方式,又称 访问类型。访问类型的性能指标从差到好依次是 system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。;
possible_keys:可能用到的索引,如果为 NULL,表示没有可能用到的索引;
key:用到的索引,如果为 NULL,表示没有使用索引;
key_len:按字节计算的索引长度,值越小,表示越快;
ref:关联关系中另一个表的列名称;
rows:查询数据返回的行数;
Extra:与关联操作有关的信息。
反例::x:
SELECT t0.product_id
FROM product t0
WHERE t0.stock_quantity >= '5';
📌应指定上下边界
正例::white_check_mark:
SELECT t0.product_id
FROM product t0
WHERE t0.stock_quantity >= '5' AND t0.stock_quantity <= '999999';
反例:❌
SELECT t0.product_id
FROM product t0
WHERE t0.product_status NOT IN ('已下架', '已删除', '无库存');
📌应指定范围
正例:✅
SELECT t0.product_id
FROM product t0
WHERE t0.product_status IN ('正常销售', '促销中', '可预订');
*使用 IN
时也控制范围大小,不推荐超过 1000
,否则影响性能,得不偿失。
反例:❌
SELECT t0.product_id
FROM product t0
WHERE t0.product_name LIKE '%化工品%';
-- 或
SELECT t0.product_id
FROM product t0
WHERE t0.product_name LIKE '%化工品原料';
正例:✅
SELECT t0.product_id
FROM product t0
WHERE t0.product_name LIKE '危险化工品%';
使用默认约束 (Default Counstraint) 填充数据的默认值
反例:❌
SELECT t0.trade_id
FROM trade_order t0
WHERE DATE(t0.gmt_create) < CURDATE();
正例:✅
SELECT t0.trade_id
FROM trade_order t0
WHERE t0.gmt_create >= DATE(NOW())
建立
(id_sex_city)组合索引
会自动建立id
、id_sex
和id_sex_ciry
三个索引。所以下面三个语句都会命中索引
:
-- statement1:
SELECT t0.user_name
FROM user t0
WHERE t0.id = '1001' AND t0.sex = '1' AND t0.ciry = 'Shanghai';
-- statement2:
SELECT t0.user_name
FROM user t0
WHERE t0.id = '1001' AND t0.sex = '1';
-- statement3:
SELECT t0.user_name
FROM user t0
WHERE t0.id = '1001';
但下列语句
,因为根据不会命中索引
组合索引
的最左前缀原则
只会生成靠左、逐渐递进的索引:
-- statement4:
SELECT t0.user_name
FROM user t0
WHERE t0.sex = '1' AND t0.ciry = 'Shanghai';
-- statement5:
SELECT t0.user_name
FROM user t0
WHERE t0.id = '1001' AND t0.ciry = 'Shanghai';
-- statement6:
SELECT t0.user_name
FROM user t0
WHERE t0.ciry = 'Shanghai';
-- 略...
(组合索引、复合索引、联合索引都是一个意思)。
SELECT t0.product_id
FROM product t0
WHERE t0.product_id = 201805010001;
(前提user_id字段加了索引)上面和下面的语句都会走索引:
SELECT t0.product_id
FROM product t0
WHERE t0.product_id = '201805010001';
因为 在
类型字段上会bigint
全表扫描
,而在varchar
上每个字符判断会走索引
,这样尽量避免全表扫描。
与 ~~float
double
~~存储数据时,可能会损失精度,进而判断的时候导致结果不准,强制
使用decimal
数据类型。
比如年龄、状态码等等,这样最大容量正值会扩大一倍。
比如中国大陆 11 位长度的手机号。
性别字段、状态,这种不同值很少的字段是不需要建索引的。
✨更多内容请参考《阿里巴巴Java开发手册》和《唯品会Java开发手册》。