## 前言
从MySQL5.6版本开始支持InnoDB引擎的全文索引,语法层面上大多数兼容之前MyISAM的全文索引模式。所谓全文索引,是一种通过建立倒排索引,快速匹配文档的方式。MySQL支持三种模式的全文检索模式:
1. 自然语言模式([IN NATURAL LANGUAGE MODE](http://dev.mysql.com/doc/refman/5.7/en/fulltext-natural-language.html)),即通过MATCH AGAINST 传递某个特定的字符串来进行检索。
2. 布尔模式([IN BOOLEAN MODE](http://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html)),可以为检索的字符串增加操作符,例如“+”表示必须包含,“-”表示不包含,“*”表示通配符(这种情况, 即使传递的字符串较小或出现在停词中,也不会被过滤掉),其他还有很多特殊的布尔操作符,可以通过如下参数控制:
~~~
mysql> show variables like '%ft_boolean_syntax%';
+-------------------+----------------+
| Variable_name | Value |
+-------------------+----------------+
| ft_boolean_syntax | + -><()~*:""&| |
+-------------------+----------------+
1 row in set (0.00 sec)
~~~
3. 查询扩展模式([WITH QUERY EXPANSION](http://dev.mysql.com/doc/refman/5.7/en/fulltext-query-expansion.html)), 这种模式是自然语言模式下的一个变种,会执行两次检索,第一次使用给定的短语进行检索,第二次是结合第一次相关性比较高的行进行检索。
目前MySQL支持在CHAR、VARCHAR、TEXT类型的列上定义全文索引。
本文只是简单的分析了全文索引涉及到的代码模块以及5.7的一些新特性,源码部分基于MySQL5.7.8-rc版本,更细节的部分并未深入。
## 创建全文索引
如下例所示,一个简单的创建带全文索引表的SQL:
~~~
create table t1 (a int auto_increment primary key, b text, fulltext(b));
~~~
磁盘上会产生多个文件:
~~~
$ls -lh /u01/my57/data/test/
total 1.3M
FTS_000000000000010b_0000000000000154_INDEX_1.ibd
FTS_000000000000010b_0000000000000154_INDEX_2.ibd
FTS_000000000000010b_0000000000000154_INDEX_3.ibd
FTS_000000000000010b_0000000000000154_INDEX_4.ibd
FTS_000000000000010b_0000000000000154_INDEX_5.ibd
FTS_000000000000010b_0000000000000154_INDEX_6.ibd
FTS_000000000000010b_BEING_DELETED_CACHE.ibd
FTS_000000000000010b_BEING_DELETED.ibd
FTS_000000000000010b_CONFIG.ibd
FTS_000000000000010b_DELETED_CACHE.ibd
FTS_000000000000010b_DELETED.ibd
t1.frm
t1.ibd
~~~
除了t1.frm和t1.ibd外,共分为以下几类表
1. FTS_000000000000010b_0000000000000154_INDEX_1~6.ibd这6个文件用于存储倒排索引,存储的是分词和位置以及document ID,根据分词的第一个字符值进行分区,映射到不同的文件中;
文件的命名规则为FTS_{TABLE_ID}_{INDEX_ID}_INDEX_{N}.ibd
2. FTS_000000000000010b_DELETED.ibd 包含已经被删除的DOC_ID,但还没从全文索引数据中删掉;
FTS_000000000000010b_DELETED_CACHE.ibd 是前者的内存缓存(但是搜索了下代码,只有当`fts_cache_t::deleted_doc_ids`被使用时,才会在sync时转储到该表中,但并没有发现任何地方使用这个对象)
3. FTS_000000000000010b_BEING_DELETED_CACHE.ibd 和 FTS_000000000000010b_BEING_DELETED.ibd,包含了已经被删除索引记录并且正在从全文索引中移除的DOC ID,前者是后者的内存版本,这两个表主要用于辅助进行OPTIMIZE TABLE时将DELETED/DELETED_CACHED表中的记录转储到其中。
4. FTS_000000000000010b_CONFIG.ibd,包含全文索引的内部信息,最重要的存储是FTS_SYNCED_DOC_ID,表示已经解析并刷到磁盘的doc id, 在崩溃恢复时,可以根据这个值判断哪些该重新解析并加入到索引cache中。
建全文索引辅助表函数参考:
~~~
ha_innobase::create
|--> create_table_info_t::create_table
|--> fts_create_common_tables
~~~
当对一个已经存在的表上创建全文索引时,InnoDB采用了fork多个线程进行并发构建全文索引项的方法,并发度由参数 `innodb_ft_sort_pll_degree` 控制。因此在restore一个全文索引表时,我们建议先建表、导入数据,再在表上创建全文索引。
参考函数:`row_merge_read_clustered_index --> row_fts_start_psort`
线程回调函数为`fts_parallel_tokenization`。
当表上存在全文索引时,就会隐式的建立一个名为FTS_DOC_ID的列,并在其上创建一个唯一索引,用于标识分词出现的记录行。你也可以显式的创建一个名为FTS_DOC_ID的列,但需要和隐式创建的列类型保持一致。
为了维护表上的全文索引信息,全文索引模块定义了大量的类来进行管理,总的来说如下图所示:
![](https://box.kancloud.cn/2015-11-15_5647dfc12c362.png)
图1\. 全文索引模块
## 普通DML及查询操作
### 插入
我们可以通过INNODB_FT_INDEX_CACHE来检查插入记录的分词:
~~~
mysql> insert into t1 values (NULL, 'hello, welcome to mysql world');
Query OK, 1 row affected (1.87 sec)
mysql> set global innodb_ft_aux_table = 'test/t1';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from INNODB_FT_INDEX_CACHE;
+---------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+---------+--------------+-------------+-----------+--------+----------+
| hello | 2 | 2 | 1 | 2 | 0 |
| mysql | 2 | 2 | 1 | 2 | 18 |
| welcome | 2 | 2 | 1 | 2 | 7 |
| world | 2 | 2 | 1 | 2 | 24 |
+---------+--------------+-------------+-----------+--------+----------+
4 rows in set (0.00 sec)
~~~
在插入一条记录时,对应的堆栈如下:
~~~
row_insert_for_mysql
|--> row_insert_for_mysql_using_ins_graph
|--> fts_trx_add_op // state = FTS_INSERT
~~~
在向原表上插入完成记录后,会去判断表上是否有全文索引(DICT_TF2_FTS),如果有的话,则将插入记录对应的doc id提取出来(`fts_get_doc_id_from_row`),并缓存到事务对象中。
### 删除
删除操作不会直接从全文索引里直接删除,因此依然可以从INNODB_FT_INDEX_CACHE中查到分词信息。
相关堆栈:
~~~
ha_innobase::delete_row
|--> row_update_for_mysql
|--> row_update_for_mysql_using_upd_graph
|--> row_fts_update_or_delete
|--> fts_trx_add_op // state = FTS_DELETE
~~~
### 更新
更新非全文索引列,不会修改FTS_DOC_ID列的值。如果更新了全文索引列,在InnoDB的实现是删除老的DOC,并插入新的DOC。
堆栈为:
~~~
ha_innobase::update_row
|--> row_update_for_mysql
|--> row_update_for_mysql_using_upd_graph
|--> row_fts_update_or_delete
|--> row_fts_do_update
|--> fts_trx_add_op // state = FTS_DELETE
|--> fts_trx_add_op // state = FTS_INSERT
~~~
可见所有DML的操作,都走接口函数`fts_trx_add_op`,划分为两种操作: FTS_INSERT及FTS_DELETE;当前事务涉及的doc id被存储到`trx->fts_trx`中,在执行SQL的过程中并没有更新全文索引,而是在事务提交时进行的。
在缓存操作时,维护了两个结构,一个是`trx->fts_trx->savepoints`,维护了事务全局的全文索引操作,另外一个是`trx->fts_trx->last_stmt`,维护的是当前SQL操作的doc id,前者在事务结束时处理,后者在SQL结束时清空。
### 查询
对于全文索引的查询,采用新的接口函数,分为两步:
1. 根据检索词搜集符合条件的doc id。
~~~
JOIN::optimize
|--> init_ftfuncs
|--> Item_func_match::init_search
|--> ha_innobase::ft_init_ext
|--> fts_query
~~~
在搜集满足查询条件的doc id时,首先读取DELETED表中记录的doc id,这些doc id随后被用做过滤。
2. 根据搜集到的doc id,找到对应的记录,使用的索引是`dict_table_t::fts_doc_id_index`,也就是建立在隐藏列FTS_DOC_ID上的唯一索引。
~~~
sub_select
|--> join_ft_read_first
|--> ha_innobase::ft_init
|--> ha_innobase::ft_read
|--> join_ft_read_next
|--> ha_innobase::ft_read
~~~
通常查询返回的结果是根据rank排序的,InnoDB的全文检索排序规则和sphinx类似,基于 BM25 和 TF-IDF算法。
rank的计算算法如下:
~~~
${IDF} = log10( ${total_records} / ${matching_records} ) // total_records表示总的行记录数,matching_records表示匹配到检索字的行记录数
${TF} 表示单词在文档中出现的次数
${rank} = ${TF} * ${IDF} * ${IDF}
~~~
IDF的计算参阅函数:`fts_query_calculate_idf`
ranking计算:`fts_query_calculate_ranking`
如果使用多个单词匹配,则把各个单词各自的rank累加起来。官方博客有[一篇文章](http://mysqlserverteam.com/rankings-with-innodb-full-text-search/)专门对此进行了介绍。
## 事务操作
事务内回滚
正在事务内回滚某个语句,或者回滚到某个savepoint时,需要将对应的操作记录也要删除。维护了`trx->fts_trx->last_stmt`,在单条SQL结束时释放(`trx_mark_sql_stat_end`)。如果SQL回滚,就根据last_stmt中维护的doc id从全局savepoints中清理掉本条SQL的doc id。
相关堆栈:
~~~
innobase_rollback --> trx_rollback_last_sql_stat_for_mysql
|--> fts_savepoint_rollback_last_stmt
|--> fts_undo_last_stmt
|--> trx_mark_sql_stat_end
|--> fts_savepoint_laststmt_refresh
~~~
回滚到savepoint
~~~
innobase_rollback_to_savepoint
|--> fts_savepoint_rollback
~~~
事务提交
相关堆栈:
~~~
trx_commit_low
|--> fts_commit // 处理trx->fts_trx->savepoints中缓存的全文索引操作
|--> fts_commit_table
|--> fts_add
|--> fts_add_doc_by_id
|--> fts_delete
|--> trx_commit_in_memory
|--> trx_finalize_for_fts
|--> trx_finalize_for_fts_table
~~~
在调用fts_commit时,会根据不同的操作类型,调用fts_add增加全文索引项,调用fts_delete删除全文索引项。
由于在插入记录时,先分词、分解成多个词插入辅助表中,因此一条insert可能产生多个小的插入,这种写入放大可能是不可承受的。InnoDB采用了一种优化的方案:创建一个内存cache,临时缓存插入操作,当cache满时再批量刷到磁盘,这样做的好处是:
* 避免重复存储相同的单词;
* cache size 通过参数`innodb_ft_cache_size`控制;
* 查询会将cache和磁盘数据进行merge。
在事务提交时,调用函数`fts_add_doc_by_id`:
* 首先根据doc id,使用doc_id所在的索引进行查询,找到刚刚插入的记录项对应的聚集索引记录;
* 遍历表上全部的聚集索引,根据全文索引对应的`fts_get_doc_t`(`fts_cache_t::get_docs`)构建`fts_doc_t`,对文档根据选择的parser进行分词(`fts_tokenize_document`函数或者`fts_tokenize_document_next`),具体的文档存储到`fts_doc_t::text`中;
* 将上一步获得的分词加入到cache中(`fts_cache_add_doc`);
* 如果当前cache的大小超过配置的`innodb_ft_cache_size`,或者全局cache的大小超过`innodb_ft_total_cache_size`(`fts_need_sync`被设置为true),则进行一次sync,将该表缓存的数据刷到全文索引文件中(fts_sync),并清空cache。
和插入相似,删除操作也可能产生大量小的删除操作,为了避免这种情况,维持一个表,来记录被删除的doc id,但记录依然存在于原文件中。删除操作的提交函数为`fts_delete`,将被删除的记录doc_id插入到DELETED辅助表中。
事务模块涉及的几个关键类包括:
![](https://box.kancloud.cn/2015-11-15_5647dfc14c563.png)
图2\. 全文索引事务模块
## 同步缓存
在满足一定条件时,全文索引需要进行一次sync操作,将数据同步到全文索引文件中,大概包含以下集中情况需要sync:
* cache数据占用的内存超过限制;
* 后台线程`fts_optimize_thread`在shutdown调用,将所有表进行一次sync;
* `ha_innobase::optimize`调用(执行optimize table);
* `row_merge_read_clustered_index`:创建一个新的临时表并读入数据后,进行一次sync调用。
同步操作的入口函数为fts_sync,大体流程为:
* 针对每个索引,调用函数`fts_sync_index`:通过函数`fts_select_index`计算写入的索引文件,再将分词节点信息写入到文件(函数`fts_write_node`), 倒排索引的记录内容使用结构体`fts_node_t`进行描述,存储结构如下图所示:
![](https://box.kancloud.cn/2015-11-15_5647dfc156b55.png)
图3\. 倒排索引结点存储结构
* 调用`fts_sync_commit`提交sync操作:
* 更新CONFIG表记录的最大SYNC的DOC ID(`fts_cmp_set_sync_doc_id`);
* 若`fts_cache_t::deleted_doc_ids`不为空,将其加入到DELETED_CACHE辅助表中(`fts_sync_add_deleted_cache`);
* 清空cache 并重新初始化。
## Optimize table
当你修改了某些配置(例如最小token size时),或者希望重组全文索引时,可以执行optimize table。由于原始optimize table操作会产生整个表的重建,耗时太久,因此InnoDB引入了一个参数`innodb_optimize_fulltext_only`来控制该行为。当开启该选项时,如果执行optimize table,就只优化全文索引,而不会去重建表,入口函数为ha_innobase::optimize:
~~~
ha_innobase::optimize
|--> fts_sync_table
|--> fts_optimize_table
~~~
首先调用函数`fts_sync_table`,将表上在内存中cache的数据刷到全文索引文件中;
然后调用函数`fts_optimize_table`,我们主要分析集中在第二步。
`fts_optimize_table`函数流程如下:
* 如果BEGING_DELETED表中没有数据(例如第一次调用optimized table),则将DELETED表中的数据转储到BEING_DELETED表中,相当于拿到了一个快照,执行的SQL操作为:
~~~
static const char* fts_init_delete_sql =
"BEGIN\n"
"\n"
"INSERT INTO $BEING_DELETED\n"
"SELECT doc_id FROM $DELETED;\n"
"\n"
"INSERT INTO $BEING_DELETED_CACHE\n"
"SELECT doc_id FROM $DELETED_CACHE;\n";
~~~
参考函数:`fts_optimize_create_deleted_doc_id_snapshot`
* 从BEING_DELETED/BEING_DELETED_CACHE表中读取已经被删除的doc id,这些doc id在随后的索引优化中将被忽略掉。
参考函数:`fts_optimize_read_deleted_doc_id_snapshot`
* 调用`fts_optimize_indexes` 对每个索引进行优化,相关堆栈如下:
~~~
fts_optimize_indexes
|--> fts_optimize_index
|--> fts_optimize_index_read_words
// 读入需要进行优化的分词,一轮优化的个数不超过innodb_ft_num_word_optimize的配置值
// 缓存的分词数据采用zlib进行压缩
|--> fts_optimize_words // 读取分词,将已经删除的doc id从其中清除,并回写到db
|--> fts_index_fetch_nodes // 逐个读取分词对应的全文索引项
|--> fts_optimize_compact
|--> fts_optimize_word // 判断是否包含被删除的doc id,并重组记录
|--> fts_optimize_write_word // 将记录写回索引,具体操作为先删除老的记录,再插入新的记录
|--> fts_config_set_index_value //更新CONFIG表的FTS_LAST_OPTIMIZED_WORD列,记录最近重组优化的分词
|--> fts_optimize_index_completed // 若上述步骤将读取的分词全部处理完了,则本轮optimize操作完成
~~~
* 当在所有索引上完成optimize后,调用fts_optimize_purge_snapshot,主要操作包括:
* 从DELETE和DELETE_CACHE表中将doc id删除,参考函数fts_optimize_purge_deleted_doc_ids
~~~
static const char* fts_delete_doc_ids_sql =
"BEGIN\n"
"\n"
"DELETE FROM $DELETED WHERE doc_id = :doc_id1;\n"
"DELETE FROM $DELETED_CACHE WHERE doc_id = :doc_id2;\n";
~~~
* 从BEING_DELETED及BEING_DELETED_CACHE中删除对应的doc id。
~~~
static const char* fts_end_delete_sql =
"BEGIN\n"
"\n"
"DELETE FROM $BEING_DELETED;\n"
"DELETE FROM $BEING_DELETED_CACHE;\n";
~~~
参考函数: `fts_optimize_purge_deleted_doc_id_snapshot`
## 后台线程
InnoDB启动时,会创建一个后台线程,线程函数为`fts_optimize_thread`,工作队列为`fts_optimize_wq`,其主要目的是在满足一定条件时,对表自动进行optimize操作。
在如下两种情况,会向`fts_optimize_wq`中增加元组:
* `fts_optimize_add_table`: 创建或打开一个新的带全文索引的表时,创建一个类型为`FTS_MSG_ADD_TABLE`并包含表对象指针的MSG,加入到`fts_optimize_wq`中,这些表禁止被从数据词典中驱逐;
* `fts_optimize_remove_table`: 删除表、DDL、释放表对象(`dict_mem_table_free`)、删除全文索引(`fts_drop_index`)等操作时,会创建一个类型为`FTS_MSG_DEL_TABLE的MEG`,加入到`fts_optimize_wq`队列中。
fts optimize线程对于FTS_MSG_ADD_TABLE类型的会将相应的表加入到调度队列,对于FTS_MSG_DEL_TABLE,则从调度队列中删除。其调度队列的成员类型为`fts_slot_t`。
当表上删除的数据量超过一千万(FTS_OPTIMIZE_THRESHOLD)行时,就会触发一次自动optimize table,但两次optimize的间隔不应低于300秒(FTS_OPTIMIZE_INTERVAL_IN_SECS)。
## 监控
我们可以通过几个INFORMATION_SCHEMA下的全文索引表来监控全文索引状态。
~~~
mysql> show tables like '%ft%';
+-------------------------------------+
| Tables_in_information_schema (%ft%) |
+-------------------------------------+
| INNODB_FT_CONFIG |
| INNODB_FT_BEING_DELETED |
| INNODB_FT_DELETED |
| INNODB_FT_DEFAULT_STOPWORD |
| INNODB_FT_INDEX_TABLE |
| INNODB_FT_INDEX_CACHE |
+-------------------------------------+
6 rows in set (0.00 sec)
~~~
想要从information_schema表中查询信息,需要先设置变量`innodb_ft_aux_table`,值为你要查询表的”dbname/tablename”。
## 全文索引停词
停词(STOP WORD)用于在分词时忽略那些常见的不重要的单词,InnoDB目前内建的停词可以从information_schema.INNODB_FT_DEFAULT_STOPWORD读取,用户也可以自己定义停词列表,方法很简单:创建一个和nformation_schema.INNODB_FT_DEFAULT_STOPWORD一模一样的表,将你想要的停词加入到其中,然后设置`innodb_ft_server_stopword_table`值为你创建的表名:”dbname/tabname”。
你也可以使用会话级别的参数`innodb_ft_user_stopword_table`来指定你想要的停词表,和上述创建规则一致,具体的参阅[官方文档](http://dev.mysql.com/doc/refman/5.7/en/fulltext-stopwords.html)。
另外配置项`innodb_ft_min_token_size`及`innodb_ft_max_token_size` 用于表示一个单词的字符长度范围,在这个范围的连续字符串才会被当作一个单词。然而如果使用ngram解析器的话,有效单词长度受参数`ngram_token_size`控制。
可以关闭参数`innodb_ft_enable_stopword`,这样在分词时也会把预设的停词考虑进去。
## InnoDB全文索引插件
从MySQL 5.7.3开始InnoDB支持全文索引插件,用户可以以Plugin的模式来定义自己的分词规则,或是引入社区开发的全文索引解析器,例如某些专业领域的分词,可能具有不同的规则。
全文索引插件有两种角色:第一种是替换内建的parser,读取输入文档,进行解析后,将分词传送给server;另一种角色是作为内建parser的协作者,可以把输入文档处理过后,再传送给内建parser。
如果你已经有一个基于MYISAM的全文索引插件了,也可以根据[这篇官方文档](http://mysqlserverteam.com/innodb-supports-plugin-parser-in-fulltext-index/)的介绍,将其修改成InnoDB全文索引插件。
## InnoDB N-gram parser
从MySQL5.7.6版本开始提供了一种内建的全文索引ngram parser,可以很好的支持CJK字符集(中文、日文、韩文),CJK有个共同点就是单词不像英语习惯那样根据空格进行分解的,因此传统的内建分词方式无法准确的对类似中文进行分词。
ngram parser内建在代码中,该解析器默安装,你可以通过指定索引属性(`WITH PARSER ngram`)来利用该parser,例如:
~~~
mysql> create table ft_test(id int, content text, fulltext (content) with parser ngram);
Query OK, 0 rows affected (0.26 sec)
~~~
N-Gram使用一种特殊的方式来进行分词,举个简单的例子,假设要对单词’abcd’进行分词,那么其分词结果为:
~~~
N=1 : 'a', 'b', 'c', 'd';
N=2 : 'ab', 'bc', 'cd';
N=3 : 'abc', 'bcd';
N=4 : 'abcd';
~~~
N取决于`ngram_token_size`的设置,默认值为2。
对于停词的处理,N-Gram和默认的parser不同,即只要每个token包含了(而不是精确匹配)停词,就不对其进行索引;另外空格总是作为一个停词,因此在分词取token时,空格会被忽略掉。
在执行查询时,用户传递的搜索词也会基于N-Gram进行分解后进行检索。 具体的例子可以参阅[官方博客](http://mysqlserverteam.com/innodb-full-text-n-gram-parser/)的描述。
除了N-gram parser外,官方也支持了另外一种名为[MeCab Parser](http://mysqlserverteam.com/innodb-full-text-mecab-parser/)的插件,主要用于日语分词,但需要手动安装。
- 数据库内核月报目录
- 数据库内核月报 - 2016/09
- MySQL · 社区贡献 · AliSQL那些事儿
- PetaData · 架构体系 · PetaData第二代低成本存储体系
- MySQL · 社区动态 · MariaDB 10.2 前瞻
- MySQL · 特性分析 · 执行计划缓存设计与实现
- PgSQL · 最佳实践 · pg_rman源码浅析与使用
- MySQL · 捉虫状态 · bug分析两例
- PgSQL · 源码分析 · PG优化器浅析
- MongoDB · 特性分析· Sharding原理与应用
- PgSQL · 源码分析 · PG中的无锁算法和原子操作应用一则
- SQLServer · 最佳实践 · TEMPDB的设计
- 数据库内核月报 - 2016/08
- MySQL · 特性分析 ·MySQL 5.7新特性系列四
- PgSQL · PostgreSQL 逻辑流复制技术的秘密
- MySQL · 特性分析 · MyRocks简介
- GPDB · 特性分析· Greenplum 备份架构
- SQLServer · 最佳实践 · RDS for SQLServer 2012权限限制提升与改善
- TokuDB · 引擎特性 · REPLACE 语句优化
- MySQL · 专家投稿 · InnoDB物理行中null值的存储的推断与验证
- PgSQL · 实战经验 · 旋转门压缩算法在PostgreSQL中的实现
- MySQL · 源码分析 · Query Cache并发处理
- PgSQL · 源码分析· pg_dump分析
- 数据库内核月报 - 2016/07
- MySQL · 特性分析 ·MySQL 5.7新特性系列三
- MySQL · 特性分析 · 5.7 代价模型浅析
- PgSQL · 实战经验 · 分组TOP性能提升44倍
- MySQL · 源码分析 · 网络通信模块浅析
- MongoDB · 特性分析 · 索引原理
- SQLServer · 特性分析 · XML与JSON应用比较
- MySQL · 最佳实战 · 审计日志实用案例分析
- MySQL · 性能优化 · 条件下推到物化表
- MySQL · 源码分析 · Query Cache内部剖析
- MySQL · 捉虫动态 · 备库1206错误问题说明
- 数据库内核月报 - 2016/06
- MySQL · 特性分析 · innodb 锁分裂继承与迁移
- MySQL · 特性分析 ·MySQL 5.7新特性系列二
- PgSQL · 实战经验 · 如何预测Freeze IO风暴
- GPDB · 特性分析· Filespace和Tablespace
- MariaDB · 新特性 · 窗口函数
- MySQL · TokuDB · checkpoint过程
- MySQL · 特性分析 · 内部临时表
- MySQL · 最佳实践 · 空间优化
- SQLServer · 最佳实践 · 数据库实现大容量插入的几种方式
- 数据库内核月报 - 2016/05
- MySQL · 引擎特性 · 基于InnoDB的物理复制实现
- MySQL · 特性分析 · MySQL 5.7新特性系列一
- PostgreSQL · 特性分析 · 逻辑结构和权限体系
- MySQL · 特性分析 · innodb buffer pool相关特性
- PG&GP · 特性分析 · 外部数据导入接口实现分析
- SQLServer · 最佳实践 · 透明数据加密在SQLServer的应用
- MySQL · TokuDB · 日志子系统和崩溃恢复过程
- MongoDB · 特性分析 · Sharded cluster架构原理
- PostgreSQL · 特性分析 · 统计信息计算方法
- MySQL · 捉虫动态 · left-join多表导致crash
- 数据库内核月报 - 2016/04
- MySQL · 参数故事 · innodb_additional_mem_pool_size
- GPDB · 特性分析 · Segment事务一致性与异常处理
- GPDB · 特性分析 · Segment 修复指南
- MySQL · 捉虫动态 · 并行复制外键约束问题二
- PgSQL · 性能优化 · 如何潇洒的处理每天上百TB的数据增量
- Memcached · 最佳实践 · 热点 Key 问题解决方案
- MongoDB · 最佳实践 · 短连接Auth性能优化
- MySQL · 最佳实践 · RDS 只读实例延迟分析
- MySQL · TokuDB · TokuDB索引结构--Fractal Tree
- MySQL · TokuDB · Savepoint漫谈
- 数据库内核月报 - 2016/03
- MySQL · TokuDB · 事务子系统和 MVCC 实现
- MongoDB · 特性分析 · MMAPv1 存储引擎原理
- PgSQL · 源码分析 · 优化器逻辑推理
- SQLServer · BUG分析 · Agent 链接泄露分析
- Redis · 特性分析 · AOF Rewrite 分析
- MySQL · BUG分析 · Rename table 死锁分析
- MySQL · 物理备份 · Percona XtraBackup 备份原理
- GPDB · 特性分析· GreenPlum FTS 机制
- MySQL · 答疑解惑 · 备库Seconds_Behind_Master计算
- MySQL · 答疑解惑 · MySQL 锁问题最佳实践
- 数据库内核月报 - 2016/02
- MySQL · 引擎特性 · InnoDB 文件系统之文件物理结构
- MySQL · 引擎特性 · InnoDB 文件系统之IO系统和内存管理
- MySQL · 特性分析 · InnoDB transaction history
- PgSQL · 会议见闻 · PgConf.Russia 2016 大会总结
- PgSQL · 答疑解惑 · PostgreSQL 9.6 并行查询实现分析
- MySQL · TokuDB · TokuDB之黑科技工具
- PgSQL · 性能优化 · PostgreSQL TPC-C极限优化玩法
- MariaDB · 版本特性 · MariaDB 的 GTID 介绍
- MySQL · 特性分析 · 线程池
- MySQL · 答疑解惑 · mysqldump tips 两则
- 数据库内核月报 - 2016/01
- MySQL · 引擎特性 · InnoDB 事务锁系统简介
- GPDB · 特性分析· GreenPlum Primary/Mirror 同步机制
- MySQL · 专家投稿 · MySQL5.7 的 JSON 实现
- MySQL · 特性分析 · 优化器 MRR & BKA
- MySQL · 答疑解惑 · 物理备份死锁分析
- MySQL · TokuDB · Cachetable 的工作线程和线程池
- MySQL · 特性分析 · drop table的优化
- MySQL · 答疑解惑 · GTID不一致分析
- PgSQL · 特性分析 · Plan Hint
- MariaDB · 社区动态 · MariaDB on Power8 (下)
- 数据库内核月报 - 2015/12
- MySQL · 引擎特性 · InnoDB 事务子系统介绍
- PgSQL · 特性介绍 · 全文搜索介绍
- MongoDB · 捉虫动态 · Kill Hang问题排查记录
- MySQL · 参数优化 ·RDS MySQL参数调优最佳实践
- PgSQL · 特性分析 · 备库激活过程分析
- MySQL · TokuDB · 让Hot Backup更完美
- PgSQL · 答疑解惑 · 表膨胀
- MySQL · 特性分析 · Index Condition Pushdown (ICP)
- MariaDB · 社区动态 · MariaDB on Power8
- MySQL · 特性分析 · 企业版特性一览
- 数据库内核月报 - 2015/11
- MySQL · 社区见闻 · OOW 2015 总结 MySQL 篇
- MySQL · 特性分析 · Statement Digest
- PgSQL · 答疑解惑 · PostgreSQL 用户组权限管理
- MySQL · 特性分析 · MDL 实现分析
- PgSQL · 特性分析 · full page write 机制
- MySQL · 捉虫动态 · MySQL 外键异常分析
- MySQL · 答疑解惑 · MySQL 优化器 range 的代价计算
- MySQL · 捉虫动态 · ORDER/GROUP BY 导致 mysqld crash
- MySQL · TokuDB · TokuDB 中的行锁
- MySQL · 捉虫动态 · order by limit 造成优化器选择索引错误
- 数据库内核月报 - 2015/10
- MySQL · 引擎特性 · InnoDB 全文索引简介
- MySQL · 特性分析 · 跟踪Metadata lock
- MySQL · 答疑解惑 · 索引过滤性太差引起CPU飙高分析
- PgSQL · 特性分析 · PG主备流复制机制
- MySQL · 捉虫动态 · start slave crash 诊断分析
- MySQL · 捉虫动态 · 删除索引导致表无法打开
- PgSQL · 特性分析 · PostgreSQL Aurora方案与DEMO
- TokuDB · 捉虫动态 · CREATE DATABASE 导致crash问题
- PgSQL · 特性分析 · pg_receivexlog工具解析
- MySQL · 特性分析 · MySQL权限存储与管理
- 数据库内核月报 - 2015/09
- MySQL · 引擎特性 · InnoDB Adaptive hash index介绍
- PgSQL · 特性分析 · clog异步提交一致性、原子操作与fsync
- MySQL · 捉虫动态 · BUG 几例
- PgSQL · 答疑解惑 · 诡异的函数返回值
- MySQL · 捉虫动态 · 建表过程中crash造成重建表失败
- PgSQL · 特性分析 · 谈谈checkpoint的调度
- MySQL · 特性分析 · 5.6 并行复制恢复实现
- MySQL · 备库优化 · relay fetch 备库优化
- MySQL · 特性分析 · 5.6并行复制事件分发机制
- MySQL · TokuDB · 文件目录谈
- 数据库内核月报 - 2015/08
- MySQL · 社区动态 · InnoDB Page Compression
- PgSQL · 答疑解惑 · RDS中的PostgreSQL备库延迟原因分析
- MySQL · 社区动态 · MySQL5.6.26 Release Note解读
- PgSQL · 捉虫动态 · 执行大SQL语句提示无效的内存申请大小
- MySQL · 社区动态 · MariaDB InnoDB表空间碎片整理
- PgSQL · 答疑解惑 · 归档进程cp命令的core文件追查
- MySQL · 答疑解惑 · open file limits
- MySQL · TokuDB · 疯狂的 filenum++
- MySQL · 功能分析 · 5.6 并行复制实现分析
- MySQL · 功能分析 · MySQL表定义缓存
- 数据库内核月报 - 2015/07
- MySQL · 引擎特性 · Innodb change buffer介绍
- MySQL · TokuDB · TokuDB Checkpoint机制
- PgSQL · 特性分析 · 时间线解析
- PgSQL · 功能分析 · PostGIS 在 O2O应用中的优势
- MySQL · 引擎特性 · InnoDB index lock前世今生
- MySQL · 社区动态 · MySQL内存分配支持NUMA
- MySQL · 答疑解惑 · 外键删除bug分析
- MySQL · 引擎特性 · MySQL logical read-ahead
- MySQL · 功能介绍 · binlog拉取速度的控制
- MySQL · 答疑解惑 · 浮点型的显示问题
- 数据库内核月报 - 2015/06
- MySQL · 引擎特性 · InnoDB 崩溃恢复过程
- MySQL · 捉虫动态 · 唯一键约束失效
- MySQL · 捉虫动态 · ALTER IGNORE TABLE导致主备不一致
- MySQL · 答疑解惑 · MySQL Sort 分页
- MySQL · 答疑解惑 · binlog event 中的 error code
- PgSQL · 功能分析 · Listen/Notify 功能
- MySQL · 捉虫动态 · 任性的 normal shutdown
- PgSQL · 追根究底 · WAL日志空间的意外增长
- MySQL · 社区动态 · MariaDB Role 体系
- MySQL · TokuDB · TokuDB数据文件大小计算
- 数据库内核月报 - 2015/05
- MySQL · 引擎特性 · InnoDB redo log漫游
- MySQL · 专家投稿 · MySQL数据库SYS CPU高的可能性分析
- MySQL · 捉虫动态 · 5.6 与 5.5 InnoDB 不兼容导致 crash
- MySQL · 答疑解惑 · InnoDB 预读 VS Oracle 多块读
- PgSQL · 社区动态 · 9.5 新功能BRIN索引
- MySQL · 捉虫动态 · MySQL DDL BUG
- MySQL · 答疑解惑 · set names 都做了什么
- MySQL · 捉虫动态 · 临时表操作导致主备不一致
- TokuDB · 引擎特性 · zstd压缩算法
- MySQL · 答疑解惑 · binlog 位点刷新策略
- 数据库内核月报 - 2015/04
- MySQL · 引擎特性 · InnoDB undo log 漫游
- TokuDB · 产品新闻 · RDS TokuDB小手册
- PgSQL · 社区动态 · 说一说PgSQL 9.4.1中的那些安全补丁
- MySQL · 捉虫动态 · 连接断开导致XA事务丢失
- MySQL · 捉虫动态 · GTID下slave_net_timeout值太小问题
- MySQL · 捉虫动态 · Relay log 中 GTID group 完整性检测
- MySQL · 答疑释惑 · UPDATE交换列单表和多表的区别
- MySQL · 捉虫动态 · 删被引用索引导致crash
- MySQL · 答疑释惑 · GTID下auto_position=0时数据不一致
- 数据库内核月报 - 2015/03
- MySQL · 答疑释惑· 并发Replace into导致的死锁分析
- MySQL · 性能优化· 5.7.6 InnoDB page flush 优化
- MySQL · 捉虫动态· pid file丢失问题分析
- MySQL · 答疑释惑· using filesort VS using temporary
- MySQL · 优化限制· MySQL index_condition_pushdown
- MySQL · 捉虫动态·DROP DATABASE外键约束的GTID BUG
- MySQL · 答疑释惑· lower_case_table_names 使用问题
- PgSQL · 特性分析· Logical Decoding探索
- PgSQL · 特性分析· jsonb类型解析
- TokuDB ·引擎机制· TokuDB线程池
- 数据库内核月报 - 2015/02
- MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
- MySQL · 社区动态· 5.6.23 InnoDB相关Bugfix
- PgSQL · 特性分析· Replication Slot
- PgSQL · 特性分析· pg_prewarm
- MySQL · 答疑释惑· InnoDB丢失自增值
- MySQL · 答疑释惑· 5.5 和 5.6 时间类型兼容问题
- MySQL · 捉虫动态· 变量修改导致binlog错误
- MariaDB · 特性分析· 表/表空间加密
- MariaDB · 特性分析· Per-query variables
- TokuDB · 特性分析· 日志详解
- 数据库内核月报 - 2015/01
- MySQL · 性能优化· Group Commit优化
- MySQL · 新增特性· DDL fast fail
- MySQL · 性能优化· 启用GTID场景的性能问题及优化
- MySQL · 捉虫动态· InnoDB自增列重复值问题
- MySQL · 优化改进· 复制性能改进过程
- MySQL · 谈古论今· key分区算法演变分析
- MySQL · 捉虫动态· mysql client crash一例
- MySQL · 捉虫动态· 设置 gtid_purged 破坏AUTO_POSITION复制协议
- MySQL · 捉虫动态· replicate filter 和 GTID 一起使用的问题
- TokuDB·特性分析· Optimize Table
- 数据库内核月报 - 2014/12
- MySQL· 性能优化·5.7 Innodb事务系统
- MySQL· 踩过的坑·5.6 GTID 和存储引擎那会事
- MySQL· 性能优化·thread pool 原理分析
- MySQL· 性能优化·并行复制外建约束问题
- MySQL· 答疑释惑·binlog event有序性
- MySQL· 答疑释惑·server_id为0的Rotate
- MySQL· 性能优化·Bulk Load for CREATE INDEX
- MySQL· 捉虫动态·Opened tables block read only
- MySQL· 优化改进· GTID启动优化
- TokuDB· Binary Log Group Commit with TokuDB
- 数据库内核月报 - 2014/11
- MySQL· 捉虫动态·OPTIMIZE 不存在的表
- MySQL· 捉虫动态·SIGHUP 导致 binlog 写错
- MySQL· 5.7改进·Recovery改进
- MySQL· 5.7特性·高可用支持
- MySQL· 5.7优化·Metadata Lock子系统的优化
- MySQL· 5.7特性·在线Truncate undo log 表空间
- MySQL· 性能优化·hash_scan 算法的实现解析
- TokuDB· 版本优化· 7.5.0
- TokuDB· 引擎特性· FAST UPDATES
- MariaDB· 性能优化·filesort with small LIMIT optimization
- 数据库内核月报 - 2014/10
- MySQL· 5.7重构·Optimizer Cost Model
- MySQL· 系统限制·text字段数
- MySQL· 捉虫动态·binlog重放失败
- MySQL· 捉虫动态·从库OOM
- MySQL· 捉虫动态·崩溃恢复失败
- MySQL· 功能改进·InnoDB Warmup特性
- MySQL· 文件结构·告别frm文件
- MariaDB· 新鲜特性·ANALYZE statement 语法
- TokuDB· 主备复制·Read Free Replication
- TokuDB· 引擎特性·压缩
- 数据库内核月报 - 2014/09
- MySQL· 捉虫动态·GTID 和 DELAYED
- MySQL· 限制改进·GTID和升级
- MySQL· 捉虫动态·GTID 和 binlog_checksum
- MySQL· 引擎差异·create_time in status
- MySQL· 参数故事·thread_concurrency
- MySQL· 捉虫动态·auto_increment
- MariaDB· 性能优化·Extended Keys
- MariaDB·主备复制·CREATE OR REPLACE
- TokuDB· 参数故事·数据安全和性能
- TokuDB· HA方案·TokuDB热备
- 数据库内核月报 - 2014/08
- MySQL· 参数故事·timed_mutexes
- MySQL· 参数故事·innodb_flush_log_at_trx_commit
- MySQL· 捉虫动态·Count(Distinct) ERROR
- MySQL· 捉虫动态·mysqldump BUFFER OVERFLOW
- MySQL· 捉虫动态·long semaphore waits
- MariaDB·分支特性·支持大于16K的InnoDB Page Size
- MariaDB·分支特性·FusionIO特性支持
- TokuDB· 性能优化·Bulk Fetch
- TokuDB· 数据结构·Fractal-Trees与LSM-Trees对比
- TokuDB·社区八卦·TokuDB团队