Month: 十一月 2017

mysql 基础知识(4) – 用户和权限

创建用户

CREATE USER 'newuser'@'%' IDENTIFIED BY 'password';

授权

GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%';

其中的 % 代表这个用户可以在任意主机登录.

SHOW GRANTS FOR newuser

用来显示一个用户的当前授权

set password for USERNAME = password('xxx')

更改用户密码

重置密码

sudo mysqld_safe --skip-grant-tables --skip-networking &
 
use mysql;
update user set authentication_string=PASSWORD("") where User='root';
update user set plugin="mysql_native_password"; # THIS LINE
flush privileges;
quit;

其他问题

EXPLAIN, slow-log

解决小内存机器 MySQL 总是 OOM 的问题

有一台512M内存的小机器总是报数据库错误, 查看了下日志是OOM了

解决方案:

一 Add swap file to cloud instance

http://www.prowebdev.us/2012/05/amazon-ec2-linux-micro-swap-space.html

  1. Run dd if=/dev/zero of=/swapfile bs=1M count=1024
  2. Run mkswap /swapfile
  3. Run swapon /swapfile
  4. Add this line /swapfile swap swap defaults 0 0 to /etc/fstab  

Some useful command related to SWAP space:

$ swapon -s   
$ free -k
$ swapoff -a
$ swapon  -a

二 limit mysql buffersize

innodb_buffer_pool_size = 8M

三 limit apache memory cosumption,editing /etc/apache2/mods-enabled/mpm_prefork.conf

<IfModule mpm_prefork_module>
    StartServers        3
    MinSpareServers     3
    MaxSpareServers     5
    MaxRequestWorkers   25
    MaxConnectionsPerChild  0
</IfModule>

django templates

# marco
 
there is no marco in django template, you just have to use include with parameters

“`
{% include “marco.html” with arg=parameter %}
“`

# variable

“`
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
“`

If a variable resolves to a callable, the template system will call it with no arguments and use its result instead of the callable.

# tags

# filters

mysql 基础知识(3) – 创建修改表和权限

创建数据库

CREATE DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

ALTER DATABASE db_name
    [[DEFAULT] CHARACTER SET charset_name]
    [[DEFAULT] COLLATE collation_name]

创建表?

CREATE TABLE table_name (
    field_name type is_null default options,
    ...
    PRIMAR KEY (id),
    INDEX/KEY index_name (field_name),
) ENGINE=InnoDB;
 
// 注意:KEY is normally a synonym for INDEX

设定 auto_increment

注意 mysql 的关键字是 auto_increment, 而 sqlite 的是 autoincrement

CREATE TABLE(...) AUTO_INCREMENT=xxx;

更改已经存在的表

ALTER TABLE SET AUTO_INCREMENT=xxx;

 

数据类型

字符串

字符串分两种,定长和变长,MySQL处理定长数据比变长数据快得多。CHAR属于定长类型,VARCHAR和TEXT属于变长类型。

  • CHAR的长度为1-255,默认为1,使用CHAR(n)指定长度
  • VARCHAR为0-255,使用VARCHAR(n)指定长度
  • TEXT为65536,MEDIUMTEXT为16k,LONGTEXT为4GB

数字

注意数字后面跟的数字,例如INT(5),并不是限制数字的存储长度,而是限制数字的展示长度(显示时填充0)!可以使用UNSIGNED指定为非负值,默认为signed

日期

使用DATETIME,不要使用TIMESTAMP,防止2038年溢出

tips

创建 modify_time/update_time 字段时使用自动更新时间

`modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

设计表要注意每个字段的正交性,不要出现一个字段表示“xx且xx”的状态。

 

更新表

rename table 'old_name' to 'new_name'

添加一列,其中的 COLUMN 关键字是 optional 的。

ALTER TABLE table_name ADD COLUMN field_name type;

更新某个字段的数据类型

Alter TABLE `tableName` MODIFY COLUMN `ColumnName` datatype(length);

比如说:

Alter TABLE `tbl_users` MODIFY COLUMN `dup` VARCHAR(120);

重命名一列

需要注意的是数据类型也需要带上

alter table `user` change `name` `first_name` varchar(128) default null;

添加不同类型的索引

ALTER TABLE table_name ADD INDEX index_name (column_list)

ALTER TABLE table_name ADD UNIQUE index_name (column_list)

ALTER TABLE table_name ADD PRIMARY KEY index_name (column_list)

需要注意的是 mysql 索引的最大长度是 255,也就是在 VARCHAR(255) 以上的列是不能添加索引的,一个改进方法就是另外添加一列存储这一列的 hash 值。

删除字段

删除索引

alter table TABLENAME drop index xxxx

——————之前笔记的分割线————————
 
 

组合索引

 
如果有一个组合索引(col_a,col_b,col_c)
 
下面的情况都会用到这个索引:

col_a = "some value";
col_a = "some value" and col_b = "some value";
col_a = "some value" and col_b = "some value" and col_c = "some value";
col_b = "some value" and col_a = "some value" and col_c = "some value";

对于最后一条语句,mysql会自动优化成第三条的样子
 
下面的情况就不会用到索引:

col_b = "aaaaaa";
col_b = "aaaa" and col_c = "cccccc";

mysql 基础知识(2) – 增删改查

我们还是使用上篇文章定义的例子来说明问题

插入数据

使用 INSERT 语句.

insert into students(**field_names) values(**VALUES), values(**VALUES);

批量插入

如果一次要插入所有数据的话, 可以直接省略前面的字段名. MySQL 可以一次插入多行数据或者一行数据, 但是这并不是SQL标准规定的. 使用批量插入可以大幅度提高性能。

在批量插入的语句中,如果有一行是错的,那么就会导致整个插入失败,可以使用 insert ignore 语句。

如果要在批量插入不同的表,可以一次执行多个语句,而不是只执行一个。

insert or update

如果要实现 insert or update 的功能,可以使用 insert on duplicate update 语句。

更新数据

使用 UPDATE 语句.

update students set math_score = 100 where first_name = 'luke';

删除数据

使用 DELETE 语句.

delete from students where name = 'luke';

参考

  1. http://www.mysqltutorial.org/mysql-insert-ignore/

C++ 字面量

C++中的字典字面量

You can actually do this:

std::map<std::string, int> mymap = {{"one", 1}, {"two", 2}, {"three", 3}};

What is actually happening here is that std::map stores an std::pair of the key value types, in this case std::pair<const std::string,int>. This is only possible because of c++11’s new uniform initialization syntax which in this case calls a constructor overload of std::pair<const std::string,int>. In this case std::map has a constructor with an std::intializer_list which is responsible for the outside braces.

So unlike python’s any class you create can use this syntax to initialize itself as long as you create a constructor that takes an initializer list (or uniform initialization syntax is applicable)

https://stackoverflow.com/a/20230177/1061155

Python 中不爽的地方

# GIL

之前用多线程都是做一些IO密集的内容, 比如爬网页的时候开一个ThreadPool, 处理速度立马就翻了几倍. 所以一直没把GIL放在心上, 前几天要跑一些处理敏感词的数据, 大概要对几百万篇文章做正则匹配. 想都没想就用了多线程, 吃饭回来发现并没有跑完, 这才想起来正则匹配这种东西是CPU密集的, 用Python的线程并没有任何卵用. 这时候换成multiprocessing.Pool速度又飚起来了, 然而使用进程池终究还是不如线程池方便, 所有传入的函数必须是marshallable, 有时候还是不能直接替换的.

# 函数式编程

没有真正的闭包, 必须使用nonlocal关键词才能实现一些闭包的功能

也没有真正的lambda表达式, 自带的lambda表达式局限非常大

# 其他

bytes的格式化输出竟然是 b’xxx’

RocksDB 基础操作教程

## 打开一个数据库

“`
#include <cassert>
#include "rocksdb/db.h"

rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
options.error_if_exists = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
assert(status.ok());

“`

通过options制定一些属性, 然后用 `rocksdb::DB::Open`打开. RocksDB 会把使用的配置保存在 `OPTIONS-xxxx` 文件中.

注意上面返回的那个status变量, 在RocksDB中所有会遇到错误的函数都会返回这个变量, 可以用来检查有没有出错.

“`
rocksdb::Status s = …;
if (!s.ok()) cerr << s.ToString() << endl;
“`

关闭数据库, 只需要简单得把指针释放就可以了: `delete db`.

## 读写数据库

基本的Put, Get, Delete:

“`
std::string value;
rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
if (s.ok()) s = db->Put(rocksdb::WriteOptions(), key2, value);
if (s.ok()) s = db->Delete(rocksdb::WriteOptions(), key1);
“`

注意其中每次都检查了操作是否成功.

每次 Get 操作都会导致至少一次的memcpy, 如果不想要这种浪费的话, 可以使用 PinnableSlice 操作.

“`
PinnableSlice pinnable_val;
rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &pinnable_val);
“`

## 原子操作

使用`WriteBatch`来构成一个原子性的操作. 什么是原子性操作总不用多说吧…原子操作不仅保证了原子性, 而且一般来说对性能也有帮助

“`
#include "rocksdb/write_batch.h"

std::string value;
rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
if (s.ok()) {
rocksdb::WriteBatch batch;
batch.Delete(key1);
batch.Put(key2, value);
s = db->Write(rocksdb::WriteOptions(), &batch);
}
“`

## 同步与异步读写

这块没看明白…

默认的是异步读写, 如果使用了`sync`这个标志, 那么就是同步读写了

“`
rocksdb::WriteOptions write_options;
write_options.sync = true;
db->Put(write_options, …);
“`

异步读写经常会比同步读写快上1000倍, 但是当机器down掉的时候, 会丢失最后的几个写入. 不过通常来说, 可以认为异步读写安全性也是够的.

除了可以使用异步读写以外, 还可以使用 `WriteBatch` 来批量读写.

## 并发

一个数据库同时只能被一个进程读写. 但是一个db实例的`Get`操作都是线程安全的, 而`WriteBatch`等操作可能需要其他一些同步机制

## Merge 操作符

待续

## Iterators

遍历所有的key

“`
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
cout << it->key().ToString() << ": " << it->value().ToString() << endl;
}
assert(it->status().ok()); // Check for any errors found during the scan
delete it;
“`

遍历[start, limit)之间的值

“`
for (it->Seek(start);
it->Valid() && it->key().ToString() < limit;
it->Next()) {

}
assert(it->status().ok()); // Check for any errors found during the scan
“`

反向遍历

“`
for (it->SeekToLast(); it->Valid(); it->Prev()) {

}
assert(it->status().ok()); // Check for any errors found during the scan
“`

## Snapshot(快照)

Snapshot 提供了当前系统在某一点的一个只读的状态表示.

“`
rocksdb::ReadOptions options;
options.snapshot = db->GetSnapshot();
… apply some updates to db …
rocksdb::Iterator* iter = db->NewIterator(options);
… read using iter to view the state when the snapshot was created …
delete iter;
db->ReleaseSnapshot(options.snapshot);
“`

注意这里通过snapshot读到的都是在做snapshot那个时间点的数据库的值.

## Slice

上面提到的 `iter->key()` 和 `iter-value()` 的返回值都是 `rocksdb::Slice` 类型的. Slice 仅仅是一个包含了长度和指针的bytearray. 它本身并不储存值, 这样也就避免了拷贝.

Slice和string的互相转换:

“`
rocksdb::Slice s1 = "hello";

std::string str("world");
rocksdb::Slice s2 = str;

std::string str = s1.ToString();
assert(str == std::string("hello"));
“`

未完待续…

RocksDB 常见问题

## RocksDB 会抛出异常吗?

不会, RocksDB会返回一个Status表示成功或者失败, 但是RocksDB并没有捕获STL中的异常, 比如bad_alloc这种

## 基础操作是线程安全的吗?

是的

## 可以使用多个进程(process)同时读写 RocksDB 吗?

不可以, 当然只读模式随意