tidb index实现
tidb的index不像mysql那样, 由于tidb对于value的获取全是kv操作, 不需要有实质的查询优化, 其只需要用来保证相应的unique等特性跟mysql表现一致即可, 所以tidb的index更多的像是一种兼容的方案.
|
|
这是Insert语句中涉及到Index的部分, 首先, 它会从插入的值中获得对应的index列, 在v.FetchValues中获得:
|
|
然后调用v.X.Create
尝试创建这个index:
|
|
我们先来看看unique index的key value, 它会把当前的recordid(这条记录唯一的id)当成value存起来, 这个在处理duplicate update的时候有用:
|
|
当index重复了, 而且其为unique的, 不允许重复的话, 那么Create会返回kv.ErrKeyExists
error, 那么从这个Index的value中找到其相应的recordid, 用于在Duplicate update的时候获取该条记录, 来进行Update某些列
如果非Unique index, 其值当前还未用上, 就随便用了一个"timestamp?"
, 来存.
kvIndex.genIndexKey
我们再来看看c.genIndexKey到底是怎么来产生index相应的key的:
|
|
参数h是recordId, indexedValues是插入值中对应Index列的几个值. 可以看到index key的结构如下:
| indexPrefix | encValue |
encValue:
可以看到, 如果是非Unique的, 那么这个index不会对插入的值造成任何约束, 也就是这条Insert一定会成功, 那么, 怎么样就不会在leveldb中找到相应的值呢, 只要把recordid绑定起来, 那么这个index key就是全局唯一的了:
|
|
如果是Unique的, 那么, 如果相同的值, 是需要报告Duplicate错误的, 那么, 就不能绑定recordid了:
|
|
为什么在插入index列中出现了nil, 就可以不用管Unique约束呢, 我们看到其注释如下:
/
See: https://dev.mysql.com/doc/refman/5.7/en/create-index.html
A UNIQUE index creates a constraint such that all values in the index must be distinct.
An error occurs if you try to add a new row with a key value that matches an existing row.
For all engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL. /
答案就是: a UNIQUE index permits multiple NULL values for columns that can contain NULL. 在之前tidb在:
|
|
中判断了这些列是否允许NULL了, 所以这里出现NULL是肯定合法的.
index列为nil的情形
问题: mysql是否所有index都为NOT NULL? 否, 只有primary有这个要求
是否所有的index都会有default value, 或者说所有的列都会有default value?
func (t *Table) AddRecord(ctx context.Context, r []interface{}) (recordID int64, err error)
也就是参数r数组里面的全部元素都不为nil?
答案: 除非是自己用insert into test(id, xxx) values(1, NULL)
, 该元素为nil以外, 其他未指定的(除了auto-increment列), 都会通过InsertIntoStmt.initDefaultValues
获得默认值.
这不是一个BUG
下面的语句错误? 这是因为 test1是 int类型
|
|
在MYSQL中执行会这样:
insert Table数据存放方式
在Table.AddRecord
是增加一行记录的接口:
|
|
mysql中的Integer Types
MYSQL支持以上的整数类型, 所以Create table的时候跟在INT后面的长度是没用的, 如INT(5), 都是只有4个字节长