我可以干运行/ sandbox sql命令吗?

时间:2014-03-30 18:42:48

标签: sql ruby-on-rails database sqlite postgresql

我正在尝试构建一个小型rails应用程序,以游戏格式向初学者教授sql。它的一部分是一个命令行,其中的用途试图解决sql的问题。在后端我想对测试数据库运行他们的sql命令,并检查结果以查看他们的命令是否正确。

我目前的想法是为课程的每个阶段创建sqlite数据库,然后在每个用户到达该阶段时为该数据库创建该数据库的副本。

我认为这会奏效,但我担心效率。

我的问题是,是否有一种有效的方法让用户运行SQL命令(包括drop,alter等),获得结果,但实际上并没有对db本身进行任何更改,实质上是一个任意的干运行sql命令。我熟悉sqlite和postgres,但我对其他数据库开放。

2 个答案:

答案 0 :(得分:9)

在Postgres中,您可以在最后回滚交易做很多事情:

BEGIN;

UPDATE foo ...:
INSERT bar ...;
SELECT baz FROM ...;
CREATE TABLE abc...;   -- even works for DDL statements
DROP   TABLE def...;
ALTER  TABLE ghi ...:

ROLLBACK;   -- !

手册中的更多内容:BEGIN ROLLBACK

请注意,有些事情无法回滚。例如,序列不会回滚。或者像dblink调用一些特殊命令。

某些命令无法在与他人的交易中运行。与CREATE DATABASEVACUUM一样。

此外,并发加载可能会产生副作用,例如死锁。但不太可能。您可以将transaction isolation level设置为您的要求,以排除任何副作用(以一定的性能成本)。

我不会用合理的数据来做这件事。意外事故的风险太大了。让用户执行任意代码是一种难以控制的风险。但对于训练环境来说,这应该足够好了。

使用模板数据库备份。如果出现问题,这是恢复基本状态的最快方法。例子(见最后一章):
Truncating all tables in a Postgres database

这也可以用作强力替代:为每个受训者提供原始的新数据库。

答案 1 :(得分:3)

虽然你可以在一个事务中运行他们的代码,然后在回滚之前尝试检查同一事务中的结果,但这会有一些挑战。

首先,如果代码中有任何错误,则事务将中止。除了“失败,这是错误信息”之外,您将无法说出任何其他信息。特别是,您将无法在错误发生之前检查部分结果。

其次,如果你在一个数据库中进行并行运行,锁定会让你感到困惑。每个会话都将获得锁,通常是对元组或整个关系的独占锁。其他会话将阻止等待锁定。这意味着您必须连续进行测试运行。这在您的环境中可能不是问题,但需要考虑。

第三,正如Erwin所说,你必须使你的检查代码对序列值不敏感,因为它们不会在回滚时重置。

出于所有这些原因,我强烈建议:

CREATE DATABASE course_username_lesson TEMPLATE course_lesson OWNER username;

...或者省略模板数据库的使用,只需让你的Rails应用程序使用每个用户的迁移设置一个空白数据库。这可能更简单,因为这意味着您不必维护模板DB。

PostgreSQL服务器对数百个数据库非常满​​意,至少如果预计它不会在峰值生产负载下执行。

您可能需要查看http://sqlfiddle.com/和许多其他现有的基于Web的SQL编辑器/培训工具,其中许多都是开源的。