【问题标题】:Creating even ranges based on values in an oracle table根据 oracle 表中的值创建偶数范围
【发布时间】:2018-09-25 02:12:49
【问题描述】:

我有一个大小为 100k 行的大表,主键的数据类型为 NUMBER。此列中填充数据的方式是使用随机数生成器。

所以我的问题是,是否有可能有一个 SQL 查询来帮助我用值范围均匀地对表进行分区。例如:如果我的列值是这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

我希望将其分成三个分区,然后我希望得到这样的输出:

Range 1          1-3
Range 2          4-7
Range 3          8-10

【问题讨论】:

  • 您的意思是物理上将表重建为分区表,还是只需要一个将返回三组数据的查询?如果您只需要三分之一的数据,mod(your_pk_column,3) 将返回 0、1 或 2。
  • @WilliamRobertson:我不想将我的表重建为分区,但我知道我应该如何根据我选择破坏表的分区数来定义一个范围。我的意思是,如果我的表有 100 条记录并且我想将它分成 5 个分区,我知道每个分区都会有 20 条记录,但我真的很想根据特定分区的列数据获取确切的起点和终点。
  • 组内的 PK 值是连续的是否重要,因为这些值是随机分配的?例如,mod(id,3) 将给出三个分组:{3,6,9}{1,4,7,10}{2,5,8}。会这样吗,还是必须是{1,2,3}{4,5,6} 等?

标签: plsql oracle11g partition


【解决方案1】:

听起来你想要WIDTH_BUCKET() 函数。 Find out more.

此查询将为您提供基于id 分为 20 个存储桶的 1250 行表的开始和结束范围:

with bkt as (
    select id
           , width_bucket(id, 1, 1251, 20) as id_bucket
    from t23
)
select id_bucket
       , min(id) as bkt_start
       , max(id) as bkt_end
       , count(*)
from bkt
group by id_bucket
order by 1
;

中间的两个参数指定最小值和最大值;最后一个参数指定桶的数量。输出是最小和最大弓之间的行,尽可能均匀地分成指定数量的桶。注意 min 和 max 参数;我发现选择不当的界限会对拆分产生奇怪的影响。

【讨论】:

  • 非常感谢您的评论。这实际上有帮助。如果我的 PK 列是 varchar 或 GUID,你能告诉我如何转换上面的列吗?
  • 软件之所以如此了不起的原因之一是它允许我们进行实验。我们可以尝试一些东西,写一些代码,看看会发生什么。很酷的是,无论发生什么,我们都学到了一些东西。实验只需要一些时间。
【解决方案2】:

此解决方案在没有 width_bucket 功能的情况下有效。虽然它更冗长而且效率肯定更低,但它会尽可能均匀地分割数据,即使缺少一些 ID 值。

CREATE TABLE t AS
 SELECT rownum AS id
   FROM dual 
CONNECT BY level <= 10;

WITH
   data AS (
      SELECT id, rownum as row_num
        FROM t
   ),
   total AS (
      SELECT count(*) AS total_rows
        FROM data
   ),
   parts AS (
      SELECT rownum as part_no, total.total_rows, total.total_rows / 3 as part_rows
        FROM dual, total 
     CONNECT BY level <= 3
   ),
   bounds AS (
      SELECT parts.part_no, 
             parts.total_rows, 
             parts.part_rows, 
             COALESCE(LAG(data.row_num) OVER (ORDER BY parts.part_no) + 1, 1) AS start_row_num,
             data.row_num AS end_row_num
       FROM data
       JOIN parts 
         ON data.row_num = ROUND(parts.part_no * parts.part_rows, 0)
   )
SELECT bounds.part_no, d1.ID AS start_id, d2.ID AS end_id
  FROM bounds
  JOIN data d1
    ON d1.row_num = bounds.start_row_num
  JOIN data d2
    ON d2.row_num = bounds.end_row_num
ORDER BY bounds.part_no;

   PART_NO   START_ID     END_ID
---------- ---------- ----------
         1          1          3
         2          4          7
         3          8         10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多