【问题标题】:Logarithm function in sqlite query?sqlite查询中的对数函数?
【发布时间】:2021-10-11 06:39:45
【问题描述】:

我真的需要使用对数函数对超过 400,000 行执行update。不幸的是,sqlite 中似乎不存在 SQL 对数函数。有什么方法可以导出对数函数或导入LOG 函数?

我知道如何做到这一点的唯一其他方法是我相信通过 python 订购 O(n^2)。这种方法会花费太长时间(我试过了,在我的慢速计算机上完成 6% 需要大约 1.5 小时)。

编辑:

我还发现了为什么花了这么长时间。数据库中的主键未标记为主键。所以我使用的代码如下:

for row in database:
    ...calculations for the row...
    ...sql update for the specific row which follows:...
    for search_row in database:
        if search_row[id] = row[id]:
            ...update values here...

令人难以置信的低效... O(n^2)

【问题讨论】:

  • 如果从数据库中读取 24k 值需要 1.5 小时,在 Python 中计算它们的日志,然后再次写回它们,那么奇怪的事情正在发生......
  • 在事务中完成所有操作可能会有所帮助。 (另外,在sqlite中有一个定义函数的API,它存在于C和TCL,不确定python)。
  • 还有一些库使用函数 API 来提供额外的函数,例如 Log():search.cpan.org/~kjetil/SQLite-More-0.10/lib/SQLite/More.pm

标签: python sqlite


【解决方案1】:

没有内置的对数函数;你必须定义你自己的函数。

如果您使用 Python,pysqliteAPSW 模块都可以做到这一点。

【讨论】:

  • 哇,成功了。我在 sqlite3 数据库中添加了 math.log 作为函数 log 并带有两个参数(以完成 log256)。查询只用了几秒钟。现在我之前的实现听起来很傻。
  • 链接已失效,但您可以简单地使用connection.create_function('log', 1, math.log10)
【解决方案2】:

事实证明,数学函数(包括对数)是在 Sqlite 中实现的,但在 Ubuntu 上的标准 Sqlite 编译中禁用。为了启用它们,您应该下载 Sqlite 源代码from here(“获取代码”)并根据说明进行编译(“编译”)。默认情况下将启用必要的选项 -DSQLITE_ENABLE_MATH_FUNCTIONS。编译后你会在构建目录中得到sqlite3 可执行文件,这应该作为本地文件运行:

$ ./sqlite3 <database-file>

我建议在编译之前安装readline,以便历史浏览(箭头)和自动完成在 Sqlite 命令行中正常工作。

sudo apt install libreadline-dev

【讨论】:

  • 请注意,在撰写本文时,此答案仅适用于最新的中继检入 (3.35.0),不适用于最新版本 (3.34.0)。不确定这是否是版本问题,或者是否总是如此。
【解决方案3】:

是什么让你认为它会是O(n^2)?如果有的话,它应该是线性的:O(n)

如果您使用自动提交模式,这将导致它如此缓慢的唯一原因 - 这将导致 SQLite 在每次更新时将缓冲区刷新到磁盘。

如果你开始事务,然后使用SELECT / UPDATE循环,最后提交,你的更新应该很快(前提是你的对数函数不是很慢)。

【讨论】:

    【解决方案4】:

    只需要它进行低精度自然排序(小数后一位小数,只精确到小数点后4位)但性能良好的可以使用:

    ( (length(count(*) * 1000 / 1000) + length(count(*) * 1258 / 1000) + length(count(*) * 1584 / 1000) + length(count(*) * 1995 / 1000) + length(count(*) * 2511 / 1000) + length(count(*) * 3162 / 1000) + length(count(*) * 3981 / 1000) + length(count(*) * 5011 / 1000) + length(count(*) * 6309 / 1000) + length(count(*) * 7943 / 1000)) / 10.0 - 1.0 )

    我在一个连接中需要它,我对连接的 n:m 表中条目数的日志感兴趣,因此我使用了“count(*)”,我计算了它的对数。

    ... ( ( ( ( (0.0 + length(count(*) * 1000 / 1000) + length(count(*) * 1258 / 1000) + length(count(*) * 1584 / 1000) + length(count(*) * 1995 / 1000) + length(count(*) * 2511 / 1000) + length(count(*) * 3162 / 1000) + length(count(*) * 3981 / 1000) + length(count(*) * 5011 / 1000) + length(count(*) * 6309 / 1000) + length(count(*) * 7943 / 1000)) / 10.0 - 1.0 ) * 10 +1 ) + ( IFNULL(stat.sum * 1.0 / (1848) , 0.9999999) ) ) / ( IFNULL(stat.count,1) + ( ( (0.0 + length(count(*) * 1000 / 1000) + length(count(*) * 1258 / 1000) + length(count(*) * 1584 / 1000) + length(count(*) * 1995 / 1000) + length(count(*) * 2511 / 1000) + length(count(*) * 3162 / 1000) + length(count(*) * 3981 / 1000) + length(count(*) * 5011 / 1000) + length(count(*) * 6309 / 1000) + length(count(*) * 7943 / 1000)) / 10.0 - 1.0 ) *10 +1 ) ) ) as rating, stat.expl as expl from ...

    可以使用任何其他整数变量来代替 'count(*)',只要确保它是整数,或者将其转换为整数。浮动的长度显然对你没有任何好处。

    这是一个肮脏的把戏,它利用整数的十进制表示的字符串长度由对数定义的事实,并提取它。但是与计算浮点数的所有数字的对数实现相比,将 int 转换为字符串并计算长度似乎相当有效,除了精度只有一位小数的缺点。我能用可移植的 sqlite 语法做的最好。

    P.S.:如果有人对如何提高精度、性能或具有可变对数基数有任何想法(而不是将其固定为以 10 为基数的第一个小数位),请发表评论。

    P.P.S:http://sqlfiddle.com/#!7/9aadc/2/0

    【讨论】:

      【解决方案5】:

      使用log10(number) 函数。

      反日志,使用power(10, number)函数。

      【讨论】:

      • 这没有回答问题,也不是正确的 Python 代码来执行 OP 查询的计算。请查看guidelines,了解如何回答问题。
      • 嗯.. 不知道为什么我的回答没有用。搜索“sqlite 查询中的对数函数”让我进入了这个页面。这应该有利于那些在 sqlite 查询中需要对数函数并来到这个页面的人。此外,使用这个sql函数是另一种方法。
      • SQLite 中没有对数函数,因此这个答案不适用于 OP 需要它做的事情。
      • 可能SQLite过去没有对数函数。但是我试过“select log10(100)”,它给出的查询结果是2,而“select power(10, 2)”的结果是100。
      • docs for the most recent release 开始,logarithmlog10 不是 SQLite3 中的基本函数。也许您使用的发行版内置了此功能,但它不在基础中,因此您的答案需要更多细节才能成为一个好的答案。如果您有其他证据,请出示,我将更改我的反对票和 cmets。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-25
      • 2017-06-18
      相关资源
      最近更新 更多