偶遇ORA-01450

这几天在测试环境部署一个适合多种操作系统多种数据库多实例的监控脚本的时候,在一台测试库上监控到一个索引失效,于是根据提示尝试online rebuild

alter index NINGOO.IDX_TEST_KPI_NAME rebuild online compute statistics;  

SQL> alter index NINGOO.IDX_TEST_KPI_NAME rebuild online compute statistics; 
alter index NINGOO.IDX_TEST_KPI_NAME rebuild online compute statistics
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01450: maximum key length (3215) exceeded

看了下索引是创建在一个varchar2(4000)的列上的:

SQL>  select table_name,column_name,column_length from all_ind_columns where index_name='IDX_TEST_KPI_NAME';

TABLE_NAME      COLUMN_NAME            COLUMN_LENGTH
--------------- ---------------------- -------------
TEST            KPI_NAME               4000

我们知道一个index key不能跨多个block,所以key的长度有限制的。但是索引既然创建成功,这个要求肯定是满足的。实际测试下,对于8K的block,这个限制应该是6398字节。

SQL>  create table test1(a varchar2(4000),b varchar2(4000));
Table created.

SQL> create index ix_test1 on test1(a,b);
create index ix_test1 on test1(a,b)
                         *
ERROR at line 1:
ORA-01450: maximum key length (6398) exceeded

那为什么4000字节的key在online rebuild的时候会有问题呢?而创建和正常rebuild操作都是正常的。

SQL>  create index ix_test1 on test1(a);
Index created.

SQL> alter index ix_test1 rebuild online;
alter index ix_test1 rebuild online
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01450: maximum key length (3215) exceeded

SQL> alter index ix_test1 rebuild;
Index altered.

原因在于IOT表的一些限制,我们可以创建一个IOT表验证一下:

SQL> create table test_iot1(a varchar2(4000),b varchar2(4000),
  2               constraint iot1_pk primary key(a,b))
  3                organization index;
create table test_iot1(a varchar2(4000),b varchar2(4000),
*
ERROR at line 1:
ORA-01450: maximum key length (3215) exceeded

Online rebuild的过程中需要创建一个临时的IOT表,所以online rebuild的index 的key的长度限制就被大大缩短了。这一点在我们设计系统的索引的时候要特别注意,如果前期设计的索引超过了IOT index key的长度限制,则后期的维护成本会更高,因为无法online rebuild,则rebuild的时候就会锁表导致业务受到较长时间的中断。

当然,实际业务场景中,在varchar2(4000)列上创建索引并不常见,如果真的需要,也可以考虑只创建部分前缀的函数索引,但这需要业务的SQL也做相应修改,这一点上,PostgreSQL直接支持的前缀索引就要灵活得多。

SQL> create index ix_test1_2 on test1(substr(a,1,100));
Index created.

SQL> alter index ix_test1_2 rebuild online;
Index altered.

对于这个问题,旺旺同学和Jonathan Lewis同学很早就有描述,只是没碰到一般很少碰到key这么长的索引而不容易注意到,再次记录下备忘。

深入浅出Flashcache(五)

前几天因为测试新版的Flashcache,为了便于监控性能指标,用Perl写了个秒级的监控程序Flashstat,一开始是通过定期获取dmsetup status的信息做解析,后来在flashcache-dev邮件列表中讨论时,Flashcache的作者Mohan Srinivasan说他已经将dmsetup status的信息暴露在/proc/flashcache_stats中,可以更加方便的解析。

实际上,不同版本的Flashcache,输出的性能指标有一些变化。较老的stable_v1版本的性能指标暴露在/proc/flashcache_stats,但是有些重要的指标没有包含进来,例如metadata ssd writes。而新版本支持一个系统中创建多个flashcache设备,因此位置修改成了/proc/flashcache/ssddev+diskdev/flashcache_stats,其中ssddev+diskdev根据实际的设备名不同而不同,例如在上一篇我们创建的模拟设备就应该是loop0+loop1,同时sysctl参数也根据设备名可以设置多组。为了兼容,flashstat针对老版本的flashcache还是解析dmsetup status的信息,而针对新版本则解析/proc中的flashcache_stats。

Flashstat的项目地址为:https://github.com/NinGoo/flashstat,和Mohan讨论过后,他已经将这个小工具接纳并merge到了主干代码,因此现在下载Flashcache的源码,已经在utils目录中包含了这个小工具,希望对Flashcache的用户有点用处。

Read more of this post

深入浅出Flashcache(四)

年底事情比较多,中断了一段时间,这一篇总算要说到Flashcache本身了。由于是内核模块,安装的时候需要内核源码树。具体的安装过程可以参考这里

make -j 4 KERNEL_TREE=/usr/src/kernels/2.6.32-131.0.15.el6.x86_64
sudo make install

最初版本的Flashcache只支持writeback,后来单独开了一个支持writethrough的分支在flashcache-wt目录,但目前最新的版本已经将write through合并到主版本,并且增加了write around策略。

最新的源码可以到Github获取。

env GIT_SSL_NO_VERIFY=true git clone https://github.com/facebook/flashcache.git

建议下载完源码后的第一件事,就是去doc下阅读flashcache-doc.txtflashcache-sa-guide.txt,保证比我则几篇blog有养分得多。

不是每个人都有SSD/PCI-E Flash的硬件,所以这里可以给大家一个构建虚拟混合存储设备的小技巧,这样即使是在自己的笔记本上,也可以轻松的模拟Flashcache的试验环境,而且随便折腾。

首先,我们可以用内存来模拟一个性能很好的Flash设备,当然这有一个缺点,就是主机重启后就啥都没了,不过用于实验测试这应该不是什么大问题。用内存来模拟块设备有两种方法,ramdisk或者tmpfs+loop device。由于ramdisk要调整大小需要修改grub并重启,这里我们用tmpfs来实现。

Read more of this post

深入浅出Flashcache(三)

前文简单介绍了block devicedevice mapper。有了这两个基础,再来看flashcache的代码,就容易理解多了。Flashcache是一个内核模块,要更清晰的理解代码,还需要了解一下内核模块编写的一些基础知识。好吧,虽然对于内核编程我完全是个门外汉,这里还是需要现学现卖下。所以这一篇还是不会切入正题,已经熟悉Linux内核模块的同学请忽略并耐心等待。

Linux内核支持动态的加载模块(Loadable Kernel Module,LKM)以完成某些特定的功能,模块编程需要按照一定的格式以便可以和内核交互。

5. 内核符号表

内核模块之间的交互需要通过特定的共享变量和函数,这些都需要输出到内核符号表。在模块编程中使用EXPORT_SYMBOL来进行定义。在内核中则使用了kernel_symbol结构来保存符号表信息。

Read more of this post

无觅相关文章插件,快速提升流量