我有一个存储过程,它在 Snowflake 中的 3 个不同表中执行 3 个 insert/select 语句:ScheduleUnion、ScheduleUnion1、ScheduleUnion2。现在,由于每个语句完成所需的时间,我想并行执行它们以减少总体执行时间。为此,我尝试在 Javascript 中使用Promise.all。我不会在这里发布所有插入语句,但这个示例很好地说明了我如何做到这一点:
CREATE OR REPLACE procedure etl."JimTest" ()
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
async function runSQL(sqlarray) {
snowflake.execute({ sqlText: sqlarray.sqltask } );
}
async function executeQuery() {
sql1 = `INSERT into ScheduleUnion Select.....`
sql2 = `INSERT into ScheduleUnion1 Select.....`
sql3 = `INSERT into ScheduleUnion2 Select.....`
const queries = [
{sqltask: sql1},
{sqltask: sql2},
{sqltask: sql3}
];
const sqlTasks = queries.map(runSQL);
await Promise.all(sqlTasks);
}
executeQuery();
return 'done';
$$
但是;我仍然看到我的插入语句一个接一个地连续运行:
我是否遗漏了参数,或者我的Javascript有问题?
可能有点晚了,但迟到总比不到好:
Snowflake 中禁用单个会话内的 JavaScript 并行性。因此,无论任何尝试从 Snowflake 存储过程中强制启动异步线程,所有调用都将按顺序执行。在 OP 的情况下,.map() 调用将生成 Promise,Promise.all() 将等待它们全部解析。但底层引擎不会以多线程方式运行,所以这一切都是毫无意义的。
为了执行多线程并行操作,必须使用外部客户端——例如一个 ETL 工具——通过外部驱动程序并行启动独立的会话线程。 Talend 和 Matillion 都很容易做到这一点。我会推荐 Matillion,因为它更易于使用并且具有更简单的部署架构。
Snowflake 仓库是一个 MPP 系统,它将根据其可用的处理能力在其队列中调度和执行命令 - 您不能强制它并行运行任何内容,并且它的运行将/可能会根据运行时可用的资源而有所不同-时间(即还有什么正在运行)。
如果查询运行速度不够快,那么您至少有 2 个 Snowflake 功能可供使用:
鉴于 Snowflake 允许所有这些都用 SQL 编写脚本,在脚本开始时,您可以增加仓库的大小(或创建/启动其他仓库),在脚本结束时,您可以减小仓库的大小(或删除/停止其他仓库)
任务可用于并行执行任务。
因为任务可以设置为以重叠模式运行:
ALLOW_OVERLAPPING_EXECUTION = TRUE | FALSE
https://docs.snowflake.com/en/user-guide/tasks-intro.html#overlapping-dag-runs https://docs.snowflake.com/en/sql-reference/sql/create-task.html#syntax
您可以创建一个执行插入的过程,然后创建一个运行该过程的任务。 在主函数中,您可以多次执行该任务。执行任务命令不会等待任务结束,它会在后台运行。
您还可以通过查询 *.information_schema.task_history 来监视正在执行的任务,并通过循环结果来等待它们完成/失败/等...并采取相应行动,或者如果全部成功执行则退出主过程。
一种选择是使用 SnowSQL 和
results=False
配置选项,它异步运行查询(无需等待结果)。 警告:这意味着您需要单独检查结果。
如果您可以将所有查询放入 SQL 文件中,它可能会像这样简单:
snowsql -o results=False -f queries.sql