前言
本文开始规范使用标记语法《Markdown 语法编写》 。
对于没有实际经验的情况来说,也应该记住基本数据类型,以便于快速上手应用。
1、Redis 数据类型
Redis 数据类型
Redis支持五种数据类型:
a.一维度
- string(字符串)-- SET / GET
- hash(哈希)-- HMSET / HGET
时间复杂度O(1):一次完成;hash可以存储对象(数组式): HSET KEY_NAME FIELD_NAME FIELD_VALUE;
b.二维度
- list(列表)-- LPUSH / [ LPOP | LRANGE | ... ]有序
- set(集合)-- SADD / [ SRANDMEMBER | SMEMBERS | ... ]无序
- zset(有序集合)-- ZADD / ZSCORE | ZRANGE [ ZRANK ]有序、double分值
2、golang 派生数据类型
a.数组和集合(map)的区别
- array数组定义、赋值
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列。
定义、make初始化类型、赋值
var variable_name [SIZE] variable_type ;自动设置大小var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance[4] = 50.0
- map集合的定义、赋值
定义、make初始化类型
var map_variable map[string]string ;使用 make 函数:map_variable := make(map[key_data_type]value_data_type)
赋值
map_variable [ "France" ] = "巴黎"
array相当于php的索引数组、而序列是齐全的,map相当于php的关联数组、无序的
b.数组和切片的区别
Go 语言切片是对数组的抽象。功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。同样类型是固定的。
- slice切片创建、初始化赋值
var identifier []type 切片不需要说明长度。或使用make()函数来创建切片:s := make([]type, len)
s :=[] int {1,2,3 }
3、mysql优化相关
MySQL编程重新认识函数、存储过程,代码参考《重新学习MySQL数据库》。
初始实验表 创建一个临时内存表,字符 utf8mb4
DROP TABLE IF EXISTS `vote_record_memory`;
CREATE TABLE `vote_record_memory` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(20) NOT NULL DEFAULT '',
`vote_num` int(10) unsigned NOT NULL DEFAULT '0',
`group_id` int(10) unsigned NOT NULL DEFAULT '0',
`status` tinyint(2) unsigned NOT NULL DEFAULT '1',
`create_time` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- 创建一个普通表,用作模拟大数据的测试用例;修改到相同类型
DROP TABLE IF EXISTS `vote_record`;
CREATE TABLE `vote_record` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(20) NOT NULL DEFAULT '' COMMENT '用户Id',
`vote_num` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '投票数',
`group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户组id 0-未激活用户 1-普通用户 2-vip用户 3-管理员用户',
`status` tinyint(2) unsigned NOT NULL DEFAULT '1' COMMENT '状态 1-正常 2-已删除',
`create_time` int(10) unsigned NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`) USING HASH COMMENT '用户ID哈希索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='投票记录表';
--alter table vote_record CHANGE create_time create_time datetime NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '创建时间'
a.创建表-索引、函数、存储过程
搬运
创建生成长度为n的随机字符串的函数;查验
DELIMITER // -- 修改MySQL delimiter:'//'
DROP FUNCTION IF EXISTS `rand_string` //
SET NAMES utf8mb4 //
CREATE FUNCTION `rand_string` (n INT) RETURNS VARCHAR(255) NO SQL --!注意这里!
BEGIN
DECLARE char_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE return_str varchar(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = concat(return_str, substring(char_str, FLOOR(1 + RAND()*62), 1));
SET i = i+1;
END WHILE;
RETURN return_str;
END //
-- 查验select rand_string(22)//
创建插入数据的存储过程
DROP PROCEDURE IF EXISTS `add_vote_record_memory` //
CREATE PROCEDURE `add_vote_record_memory`(IN n INT)
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE vote_num INT DEFAULT 0;
DECLARE group_id INT DEFAULT 0;
DECLARE status TINYINT DEFAULT 1;
WHILE i < n DO
SET vote_num = FLOOR(1 + RAND() * 10000);
SET group_id = FLOOR(0 + RAND()*3);
SET status = FLOOR(1 + RAND()*2);
INSERT INTO `vote_record_memory` VALUES (NULL, rand_string(20), vote_num, group_id, status, NOW());
SET i = i + 1;
END WHILE;
END //
CREATE PROCEDURE `copy_data_from_tmp`(IN n INT)
BEGIN
DECLARE lastid INT DEFAULT 0;
SELECT IFNULL(MAX(id), 0) INTO lastid FROM `vote_record`;
INSERT INTO `vote_record` SELECT * FROM `vote_record_memory` where id > lastid LIMIT n;
END //
DELIMITER ; -- 改回默认的 MySQL delimiter:';'
- 调用
-- 调用存储过程 生成10W条数据(2 min 3.69 sec第二次运行,80w 16 min 41.58 sec)
CALL add_vote_record_memory(100000);
-- 复制数据(0.87 sec第二次运行,80w 9.49 sec)
CALL copy_data_from_tmp(100000);
修改参数,调整2表数据到100w。
b.explain用法
explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描。
EXPLAIN 作用于 SELECT, DELETE, INSERT, REPLACE, 和UPDATE 语句)(mysql版本8.0.12+,旧只有 SELECT)。官方输出格式:EXPLAIN输出格式:
Column | JSON Name | Meaning |
---|---|---|
id | select_id | 该SELECT标识符;如果是子查询,id的序号会递增,即id值越大优先级越高,越先被执行 |
select_type | 没有 | 该SELECT类型;主要是用于区别普通查询、联合查询、子查询等的复杂查询 |
table | table_name | 输出行的表;可能是表名、derived+id的衍生表 |
partitions | partitions | 匹配的分区,非分区表时mull |
type | access_type | 连接类型 |
possible_keys | possible_keys | 可供选择的索引 |
key | key | 实际选择的指数 |
key_len | key_length | 所选键的长度 |
ref | ref | 列与索引进行比较 |
rows | rows | 估计要检查的行,对于InnoDB表格,此数字是估算值,可能并不总是准确的 |
filtered | filtered | 按表条件过滤的行的百分比 |
Extra | 没有 | 附加信息 |
文档《创建 PROCEDURE 和 FUNCTION 的语法》,斜体备注部分参考《[MySQL高级](一) EXPLAIN用法和结果分析》。
c.官方文档:优化SELECT语句
MYSQL8.0.12(通过lnmp安装) 性能测试:
select * from vote_record;
-- 1000000 rows in set (0.51 sec)
select * from vote_record where vote_num > 1000;
-- 899936 rows in set (0.50 sec)
优化的内容很多,下篇单独列出。
d.事务原子性与锁
有疑问加站长微信联系(非本文作者)