我刚刚在我的网站http://sqlfiddle.com上推出了一项功能,允许用户查看其查询的原始执行计划。对于 PostgreSQL、MySQL 和(在某种程度上)Oracle,查看原始执行计划输出似乎很容易理解。但是,如果您查看 SQL Server 的执行计划输出(使用 生成SET SHOWPLAN_XML ON),即使对于相对简单的查询,也有大量的 XML 需要处理。这是一个示例(取自此“小提琴”的最后一个查询的执行计划:http : //sqlfiddle.com/#!3/ 1fa93/1):
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.1" Build="10.50.2500.0">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementText="
select * from supportContacts" StatementId="1" StatementCompId="1" StatementType="SELECT" StatementSubTreeCost="0.0032853" StatementEstRows="3" StatementOptmLevel="TRIVIAL" QueryHash="0x498D13A3874D9B6E" QueryPlanHash="0xD5DDBD3C2D195E96">
<StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false"/>
<QueryPlan CachedPlanSize="16" CompileTime="0" CompileCPU="0" CompileMemory="72">
<RelOp NodeId="0" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="3" EstimateIO="0.003125" EstimateCPU="0.0001603" AvgRowSize="42" EstimatedTotalSubtreeCost="0.0032853" TableCardinality="3" Parallel="0" EstimateRebinds="0" EstimateRewinds="0">
<OutputList>
<ColumnReference Database="[db_1fa93]" Schema="[dbo]" Table="[supportContacts]" Column="id"/>
<ColumnReference Database="[db_1fa93]" Schema="[dbo]" Table="[supportContacts]" …Run Code Online (Sandbox Code Playgroud) 背景:我在http://sqlfiddle.com 上工作(我的网站)上工作,并试图防止那里可能出现的一种滥用途径。我希望通过询问我目前正在解决的问题,我不会无意中使潜在的虐待变得更糟,但是你能做什么?我相信你们。
我想阻止任何用户在给定的事务块内发出显式的“提交”调用。从 SQL Fiddle 的上下文来看,事务块是在右侧面板上执行的代码。基本上,我正在循环执行一个纯文本 SQL 命令列表,并且我想确保它们所做的所有更改都将在批处理结束时回滚。通常,他们的更改会回滚,但有时文本中会有明确的“提交”语句,因此我的回滚当然不起作用。这种显式提交很可能来自用户试图破坏 SQL Fiddle 上的架构,因此其他人会看到错误。
主要期望结果:如果可能,我想在 JDBC 级别禁用显式提交。这是因为我要支持多个数据库后端供应商,当然每个供应商在低级别都有自己的怪癖。
回退选项:如果无法将 JDBC 配置为禁用显式提交,那么我愿意接受在为以下每个后端处理批处理时检测显式提交的解决方案:SQL Server、Oracle、MySQL 和 PostgreSQL。
对于 SQL Server,我想到了这个解决方案:在我执行它之前解析语句的 XML 查询计划,并检查是否存在与此 XPath 匹配的条目:
//*[@StatementType="COMMIT TRANSACTION"]
Run Code Online (Sandbox Code Playgroud)
我认为这对 SQL Server 非常有效。但是,这种方法不适用于其他数据库类型。Oracle 用于显式提交的 XML 执行计划输出并未提及您正在运行提交语句这一事实(而是简单地重复它提交的查询的执行计划输出)。PostgreSQL 和 MySQL 根本不为显式提交提供任何执行计划输出(XML 或其他)。
这让我需要检查“提交”一词的实际语句。这会起作用,除非可能有各种变化:
declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);
Run Code Online (Sandbox Code Playgroud)
上面是 SQL Server 的一个例子(我可以解决),但我猜想类似的事情对于 Oracle、MySQL 和 PostgreSQL 也是可能的。我在这个假设上错了吗?也许他们不允许“动态”提交语句?随意使用 SQL Fiddle(最好不是示例模式或其他人可能正在使用的模式)来查看是否可以在 Oracle、MySQL 和 PostgreSQL 中进行类似的操作。如果没有,也许简单的字符串检测可能适用于那些。
还有一种可能
我想到了另一个选择 - 如果您知道一种将这些数据库中的任何一个设置为只读模式的方法,例如在该模式下无法提交任何内容,那也可以。我仍然需要允许启动事务并在其中运行代码,只要在该模式下不能提交任何内容。那可能吗?
更新
我最近学到的 - 这实际上不是 PostgreSQL …
我正在尝试json_extract_path_text()使用citext模块制作不区分大小写的版本。
我希望这是一个围绕内置函数的简单包装器,唯一的区别是它接受citext作为第一个参数而不是json. 我希望这是对本机实现的直接传递,只需事先进行类型转换。这是我到目前为止所拥有的:
create extension citext;
create or replace function json_extract_path_text ( string citext, variadic params text[]) RETURNS text IMMUTABLE AS
$$
BEGIN
SELECT json_extract_path_text(string::json, params);
END;
$$
LANGUAGE 'plpgsql';
Run Code Online (Sandbox Code Playgroud)
但是,由于类型不匹配,这不能正常工作:
Run Code Online (Sandbox Code Playgroud)ERROR: function json_extract_path_text(json, text[]) does not exist LINE 1: SELECT json_extract_path_text(string::json, params) ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. QUERY: SELECT json_extract_path_text(string::json, params) CONTEXT: PL/pgSQL function json_extract_path_text(citext,text[]) line 3 …
在 PostgreSQL 9.3 中,我试图在一个很少使用的(占总记录的 0.00001%)布尔列上创建一个有效的索引。为此,我在 SO 上发现了这篇文章: https //stackoverflow.com/a/12026593/808921
我正在尝试利用 Erwin Brandstetter 推荐的 PostgreSQL 的“部分索引”功能。我已经有一个包含几百万条记录的表,我想将索引添加到该表中,如下所示:
CREATE INDEX schema_defs_deprovision ON schema_defs (deprovision)
WHERE deprovision = 0;
Run Code Online (Sandbox Code Playgroud)
(绝大多数记录都会有 deprovision = 1)
问题是,当我尝试将此索引与最简单的查询一起使用时,PostgreSQL 就好像它不存在一样:
explain select * from schema_defs where deprovision = 0;
Seq Scan on schema_defs (cost=0.00..1.05 rows=1 width=278)
Filter: (deprovision = 0)
Run Code Online (Sandbox Code Playgroud)
真正奇怪的是,我发现如果这个索引是在表中有数据之前创建的,那么它确实可以正常工作。不相信我?以下是一些证明这一点的 SQL Fiddle 条目:
插入后创建的部分索引(索引不起作用)
插入前创建的部分索引(索引正常工作)
在这两个中,只需展开“查看执行计划”链接即可查看我在说什么。
所以,我的问题是 - 我必须做什么才能让 PostgreSQL 在创建索引之前开始在其中包含数据的表上使用部分索引?
顺便说一句,我也是 SQL Fiddle 的开发人员,这个问题与我正在为此进行的一项新开发工作有关。
我希望能够终止给定用户的活动会话,然后删除该用户,并在单个数据库调用中执行此操作。这是我到目前为止所拥有的:
DECLARE
cursor c is select *
from v$session
where username = 'USER_9FFB9';
c_row c%ROWTYPE;
begin
open C;
loop
FETCH c INTO c_row;
EXIT WHEN c%NOTFOUND;
execute immediate 'alter system kill session ''' ||
c_row.sid || ',' || c_row.serial# || '''';
execute immediate 'drop user user_9FFB9 cascade';
end loop;
end;
/
Run Code Online (Sandbox Code Playgroud)
这样做的问题是,当我在终止会话调用后立即添加 drop user 调用时,我会返回此错误:
ORA-01940: cannot drop a user that is currently connected
Run Code Online (Sandbox Code Playgroud)
但是,如果我在单独的语句中仅等待几秒钟后执行 drop user 语句,它就可以正常工作。我需要做什么才能终止会话并一次性删除用户?v$session 上是否有我应该做的循环,检查它是否仍然打开?
更新 我已经将我的脚本更新为:
DECLARE
cursor c is select *
from v$session
where …Run Code Online (Sandbox Code Playgroud) postgresql ×3
oracle ×2
array ×1
functions ×1
index ×1
jdbc ×1
mysql ×1
parameter ×1
sql-server ×1
statistics ×1
transaction ×1