在 Amazon Redshift 中存储极小的值

Posted

技术标签:

【中文标题】在 Amazon Redshift 中存储极小的值【英文标题】:Storing extremely small values in Amazon Redshift 【发布时间】:2017-03-10 17:31:25 【问题描述】:

我正在使用以下命令在Amazon Redshift 中创建一个表:

CREATE TABLE asmt.incorrect_question_pairs_unique 
AS
SELECT question1,
       question2,
       occurrences,
       occurrences / (SUM(occurrences)::FLOAT) OVER () AS prob_q1_q2
FROM (SELECT question1,
             question2,
             SUM(occurrences) AS occurrences
      FROM asmt.incorrect_question_pairs
      GROUP BY question1,
               question2
      HAVING SUM(occurrences) >= 50)

我也尝试了一个替代方案:

CREATE TABLE asmt.incorrect_question_pairs_unique 
    AS
    SELECT question1,
           question2,
           occurrences,
           occurrences::float / SUM(occurrences) OVER () AS prob_q1_q2
    FROM (SELECT question1,
                 question2,
                 SUM(occurrences) AS occurrences
          FROM asmt.incorrect_question_pairs
          GROUP BY question1,
                   question2
          HAVING SUM(occurrences) >= 50)

我希望prob_q1_q2 列成为float 列,这就是我将分母/分子转换为float 的原因。但在结果表中,我在该列中得到全零。

我想指出SUM(occurrences) 大约等于10 Billion,因此prob_q1_q2 列将包含非常小的值。有没有办法在Amazon Redshift 中存储这么小的值?

如何确保列中的所有值都不为零float

任何帮助将不胜感激。

【问题讨论】:

试试occurences::float / sum() ... 不,仍然是零。 我想指出SUM(occurrences) 的数量将超过10Billion。那么这些零是否有可能因为occurrences::float / SUM(occurrences)太小而显示为零? 你对那里的窗口函数的意图是什么? float 类型(8 字节)应该能够以至少 15 位的精度存储从 1E-307 到 1E+308 的值。尝试将部门的两个部分都转换为float。 postgresql.org/docs/9.1/static/datatype-numeric.html 【参考方案1】:

方法 1 - 我也遇到了同样的问题!在我的例子中,它是数百万行,所以我将结果乘以 10000。每当我想从该列中选择值时,我都会在 select 语句中除以 10000 以使其相等。 我知道这不是完美的解决方案,但对我有用。方法 2 - 我创建了一个具有 Numeric(12,6) 数据类型的示例表,并在导入结果时设置与您的类似,我可以看到浮点值高达 6 位十进制精度。

我猜,当您使用 create table AS 命令时,转换不起作用,您需要创建指定数据类型的表,该数据类型强制将结果集存储到某个精度级别。 它很奇怪!相同的选择如何返回 0.00,但当插入具有强制列的表时,它返回 0.00333。 如果我做出了错误的假设,请发表评论,我会重新调整答案。

【讨论】:

【参考方案2】:

臭虫,

您可能获得的数字太小,无法存储在 FLOAT 类型的 Amazon Redshift 中。尝试改用 DECIMAL,它不可能存储你的值,它是一个 128 位变量。

它的工作方式如下,如果值太大或在您的情况下太小并且超过您的类型的最大/最小值,则修剪最后一位数字,然后将新的(修剪的)值存储在您类型的变量/列。 当它削减一个很大的价值时,你几乎没有损失,可以说你从 200 亿美元中削减了 20 美分,你不会受到太大的伤害。但是在您的情况下,当数字太小时,您可以在修剪最后一位数字以适合类型时丢失所有内容 (例如,一个类型最多可以存储 5 位数字,并且您希望在此类型的变量/列中存储 0.000009 的值。您的值不适合该类型,因此它从最后 2 位数字中修剪,因此它可以适合并且你会收到一个新值 0.0000 )

因此,如果您按照我的想法将 ::float 更改为 ::decimal 应该可以解决您的问题。 附言十进制可能需要指定它的大小 f.e.十进制(127,100)

【讨论】:

【参考方案3】:

试试:

select cast(num1 as float) / cast(num2 as float);

这将为您提供最多 2 位小数的结果(默认情况下),但会占用您的一些处理时间。做任何其他事情都会将小数部分四舍五入。

【讨论】:

即使select 10::float / 3 给出相同的结果。但在我的情况下不起作用。【参考方案4】:

You can have up to 38 digits in a DECIMAL/NUMERIC column with of 37 digits of scale.

CREATE TEMP TABLE precision_test (test NUMERIC(38,37)) DISTSTYLE ALL
;
INSERT INTO precision_test 
SELECT CAST( 0.0000000000000000000000000000000000001 AS NUMERIC(38,37))  test
;
SELECT * FROM precision_test
;
--Returns 0.0000000000000000000000000000000000001

【讨论】:

以上是关于在 Amazon Redshift 中存储极小的值的主要内容,如果未能解决你的问题,请参考以下文章

amazon redshift 中存储的特定行的默认值在哪里?

Amazon redshift 存储过程,CONTINUE 不能在循环外使用;

Amazon Redshift 如何从列式存储中重建一行?

Amazon Redshift 是不是有自己的存储后端

没有函数或存储过程的 Amazon RedShift 中的 Upsert

Amazon Redshift 存储过程调用