我应该如何使用Oracle中的varchar2列对索引进行范围分区?这是个坏主意吗?

时间:2009-08-16 00:49:28

标签: oracle oracle10g partitioning

我正在使用Oracle 10g企业版。

Oracle数据库中的表存储另一个文本列的soundex值表示。我们使用自定义soundex实现,其中soundex值比传统soundex算法(例如Oracle使用的算法)生成的更长。这真的不是重点。

基本上我有一个varchar2列,其值包含单个字符,后跟动态数字值(例如'A12345','S382771'等)。该表由另一列分区,但我想将一个分区索引添加到soundex列,因为它经常被搜索。当尝试使用soundex列的第一个字符添加范围分区索引时,它工作得很好:

create index IDX_NAMES_SOUNDEX on NAMES_SOUNDEX (soundex)
global partition by range (soundex) (
    partition IDX_NAMES_SOUNDEX_PART_A values less than ('B'),  -- 'A%'
    partition IDX_NAMES_SOUNDEX_PART_B values less than ('C'),  -- 'B%'
    ...
);

但是,为了更均匀地分配分区的大小,我想通过前两个字符定义一些分区,如下所示:

create index IDX_NAMES_SOUNDEX on NAMES_SOUNDEX (soundex)
global partition by range (soundex) (
    partition IDX_NAMES_SOUNDEX_PART_A5 values less than ('A5'), -- 'A0% - A4%'
    partition IDX_NAMES_SOUNDEX_PART_A values less than ('B'),   -- 'A4% - A9%'
    partition IDX_NAMES_SOUNDEX_PART_B values less than ('C'),   -- 'B%'
    ...
);

我不确定如何使用varchar2列正确区分范围。我确信这不是一个理想的选择,所以也许有人可以推荐一个更好的解决方案。这是我表中soundex数据的分布:

-----------------------------------
|  SUBSTR(SOUNDEX,1,1)  |  COUNT  |
-----------------------------------
|                    A  | 6476349 |
|                    B  |  854880 |
|                    D  |  520676 |
|                    F  | 1200045 |
|                    G  |  280647 |
|                    H  | 3048637 |
|                    J  |  711031 |
|                    K  | 1336522 |
|                    L  |  348743 |
|                    M  | 3259464 |
|                    N  | 1510070 |
|                    Q  |  276769 |
|                    R  | 1263008 |
|                    S  | 3396223 |
|                    V  |  533844 |
|                    W  |  555007 |
|                    Y  |  348504 |
|                    Z  | 1079179 |
-----------------------------------

正如您所看到的,分布不均匀分布,这就是为什么我想使用前两个字符而不是第一个字符来定义范围分区。

建议?

谢谢!

3 个答案:

答案 0 :(得分:4)

你究竟是什么问题?

难道你不知道如何将你的桌子分成n个等分以避免歪斜?

你可以用分析函数percentile_disc()来做到这一点。

这里是一个n = 100的SQL PLUS示例,我承认它不是很复杂,但它可以完成这项工作。

set pages 0
set lines 200

drop table random_strings;

create table random_strings 
as 
select upper(dbms_random.string('A', 12)) rndmstr
from dual 
connect by level < 1000;


spool parts

select 'select '||level||'/100,percentile_disc('||level||
       '/100) within group (order by RNDMSTR) from random_strings;' 
       sql_statement
from dual 
connect by level <= 100
/

spool off

这将在文件parts.lst中输出:

select 1/100,percentile_disc(1/100) within group (order by RNDMSTR) from random_strings;                                                                                                                
select 2/100,percentile_disc(2/100) within group (order by RNDMSTR) from random_strings;                                                                                                                
select 3/100,percentile_disc(3/100) within group (order by RNDMSTR) from random_strings;                                                 
...
select 100/100,percentile_disc(100/100) within group (order by RNDMSTR) from random_strings;                                                 

现在您可以运行脚本parts.lst来获取分区值。每个分区最初将包含1%的数据。

脚本parts.lst将输出:

   ,01 AJUDRRSPGMNP
   ,02 AOMJZQPZASQZ
   ,03 AWDQXVGLLUSJ
   ,04 BIEPUHAEMELR
   .... 
   ,99 ZTMHDWTXUJAR
   1   ZYVJLNATVLOY

答案 1 :(得分:1)

除了SOUNDEX值之外,分区键是否正在搜索表?或者只是通过SOUNDEX专栏进行搜索?

如果您只是想在分区之间实现均匀的数据分配,您是否考虑过使用散列分区而不是范围分区?假设您为分区数量选择2的幂,那么应该在分区之间为您提供非常均匀的数据分布。

答案 2 :(得分:0)

跟我说说!  你能告诉我你分割这张桌子的原因是什么吗?听起来它是一个OLTP表,可能不需要分区。我们不想仅仅分区来说我们是分区的。通过对此表进行分区来告诉我您要完成的任务,我可以帮助您选择正确的分区方案。分区不等于更快的查询。在某些情况下,它实际上会导致查询速度变慢。

我在上面看到了一些您的其他想法,我认为您不需要对表格进行分区。如果您的查询将在整个分区上进行聚合,那么您可能需要进行分区。如果您要拥有数亿行数据,则可能需要对其进行分区以帮助进行DBA维护。如果您只是希望查询快速运行,那么主键索引就足够了。请让我知道

只需在所需列上创建一个全局索引。