AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 278835
Accepted
Lennart - Slava Ukraini
Lennart - Slava Ukraini
Asked: 2020-10-29 14:45:35 +0800 CST2020-10-29 14:45:35 +0800 CST 2020-10-29 14:45:35 +0800 CST

检测矛盾

  • 772

我找到了我 2011 年的一些旧笔记,并且我还重新阅读了 @lukas-eder 的优秀文章10 Cool SQL Optimisations That do not Depending the Cost Model。所以我想我会再记笔记。场景很简单Fiddle

create table emp ( 
    emp_no int not null primary key, 
    title varchar(10) not null, 
    salary int not null, 
        check (emp_no > 0), 
        check (title in ('BOSS','WORK'))
);

insert into emp with recursive t (n) as (
    values (1) 
    union all 
    select n+1 from t where n+1 < 1000
) select n, case when mod(n,10) = 0 then 'BOSS' else 'WORK' end, 
            case when mod(n,10) = 0 then 110 else 0 end + mod(n,90) 
from t;

现在,给定规则:

 (TITLE = BOSS) implies (SALARY > 100)

和

 (TITLE = WORK) implies (SALARY <= 100)

可以实现为:

-- (TITLE = BOSS) => (SALARY > 100)
alter table emp add constraint cc1 
    CHECK ( (title <> 'BOSS' OR salary > 100) );
-- (TITLE = WORK) => (SALARY <= 100)
alter table emp add constraint cc2
    CHECK ( (title <> 'WORK' OR salary <= 100) );

和查询:

select * 
from emp 
where title = 'BOSS' and salary <= 100

DBMS 能否发现矛盾,并在不接触数据的情况下返回空结果集?

Let A = ( title = ’BOSS’ ), B = ( salary > 100 )

select * from emp where (A ^ ~B)                    
select * from emp where (A ^ ~B) ^ (~A v B)           # by cc1 
select * from emp where (A ^ ~B ^ ~A) v (A ^ ~B ^ B)    
select * from emp where (FALSE ^ ~B) v (A ^ FALSE)      
select * from emp where (FALSE) v (FALSE)           
select * from emp where (FALSE)

我试过 Postgres 13(见上面的小提琴)

Seq Scan on emp  (cost=0.00..26.50 rows=2 width=46) (actual time=0.134..0.134 rows=0 loops=1)
  Filter: ((salary <= 100) AND ((title)::text = 'BOSS'::text))
  Rows Removed by Filter: 999
Planning Time: 0.312 ms
Execution Time: 0.149 ms

和 DB2 11.5.4.0:

Optimized Statement:
-------------------
SELECT 
  Q1.EMP_NO AS "EMP_NO",
  Q1.TITLE AS "TITLE",
  Q1.SALARY AS "SALARY" 
FROM 
  DB2INST1.EMP AS Q1 
WHERE 
  (Q1.SALARY <= 100) AND 
  (Q1.TITLE = 'BOSS')

Access Plan:
-----------
        Total Cost:             51.8267
        Query Degree:           1


      Rows 
     RETURN
     (   1)
      Cost 
       I/O 
       |
     90.2441 
     TBSCAN
     (   2)
     51.8267 
        4 
       |
       999 
 TABLE: DB2INST1
       EMP
       Q1

但两者都没有这样做。任何其他可以发现矛盾并采取行动的 DBMS?这当然比现实世界的问题更有趣,但仍然如此。

编辑:@federico-razzoli 在他的回答中建议的约束也不起作用:

alter table emp add constraint cc1
    check ((title = 'BOSS' and salary > 100) or 
           (title = 'WORK' AND salary <= 100));

并且相同的查询仍然会导致表访问

 Rows 
 RETURN
 (   1)
  Cost 
   I/O 
   |
 90.2441 
 TBSCAN
 (   2)
 51.8267 
    4 
   |
   999 

表:DB2INST1 EMP Q1

optimization rdbms
  • 2 2 个回答
  • 122 Views

2 个回答

  • Voted
  1. Federico Razzoli
    2020-10-30T03:43:53+08:002020-10-30T03:43:53+08:00

    你的问题很好,但它跳过了一步。您假设查询计划器(或优化器,取决于您喜欢的术语)可以考虑所有 CHECK,并合并它们。

    所以你有了:

    check (title in ('BOSS','WORK'))
    

    和:

    CHECK ( (title <> 'BOSS' OR salary > 100) )
    CHECK ( (title <> 'WORK' OR salary <= 100) )
    

    你假设规划者应该能够知道:

    CHECK ((title = 'BOSS' and salary > 100) or title = 'WORK' AND salary <= 100)
    

    这可能是这种情况,也可能不是。

    一般来说,您的答案取决于您使用的技术。MySQL 和 MariaDB 不考虑 CHECK。其他一些技术可能会这样做。您必须测试您感兴趣的技术。

    • 1
  2. Best Answer
    Lennart - Slava Ukraini
    2020-10-31T06:26:41+08:002020-10-31T06:26:41+08:00

    以下是一些 DBMS 如何处理问题中的约束的总结。还测试了其他 3 个查询:

    1.  select * 
        from emp 
        where title = 'BOSS' and salary <= 100
    
    2.  select * 
        from emp 
        where title = 'BOSS' and salary <= 100 
          and False
    
    3.  select * 
        from emp 
        where title = 'BOSS' and salary <= 100 
          and ( NOT (title = 'BOSS' AND salary <= 100) )
    
    4. select *  
       from emp 
       where title = 'BOSS' and salary <= 100 
         and ( (title <> 'BOSS' OR salary > 100) )
    

    Db2 V11.5.4.0

    未能识别 q1 中的矛盾,成功识别 q2、q3、q4

    db2 "explain plan for select ..."
    db2exfmt -d nya -1
    [...]
    
    Access Plan:
    
    -----------
    Total Cost:             51.8267
    Query Degree:           1
    
    
      Rows 
     RETURN
     (   1)
      Cost 
       I/O 
       |
     90.2441 
     TBSCAN
     (   2)
     51.8267 
        4 
       |
       999 
    TABLE: DB2INST1
       EMP
       Q1
    

    2,3,4。

    Optimized Statement:
    -------------------
    SELECT 
      NULL AS "EMP_NO",
      NULL AS "TITLE",
      NULL AS "SALARY" 
    FROM 
      (VALUES
      ) AS Q1 
    WHERE 
      (FALSE = TRUE)
    
    Access Plan:
    -----------
        Total Cost:             7.58112e-05
        Query Degree:           1
    
    
       Rows 
      RETURN
      (   1)
       Cost 
        I/O 
        |
         0 
      TBSCAN
      (   2)
    1.27533e-05 
         0 
        |
         0 
    TABFNC: SYSIBM  
      GENROW
    

    玛丽亚数据库 10.5

    未能识别查询 1、3、4 中的矛盾,查询 2 成功

    小提琴 MariaDB

    1,3,4。

        Extra
        Using where
    
    1.  Extra
       Impossible WHERE
      

    MySQL 8.0

    未能识别查询 1、3、4 中的矛盾,查询 2 成功

    小提琴 MySQL

    1,3,4。

        Extra
        Using where
    
    1.  Extra
       Impossible WHERE
      

    甲骨文 18c

    不是 100% 确定如何解释该计划,但它表示所有 4 个查询的 TABLE ACCESS Full 所以我猜这意味着它失败了 1,2,3,4

    小提琴甲骨文 18c

    Postgres 13

    未能识别 q1、q3、q4 中的矛盾,成功用于 q2

    1,3,4。查询计划 Seq Scan on emp (cost=0.00..26.50 rows=2 width=46) Filter: ( ...

    2. QUERY PLAN Result (cost=0.00..0.00 rows=0 width=0) One-Time Filter: false

    小提琴 Postgres

    SQL 服务器 2019

    未能识别 q1、q3、q4 中的矛盾,成功用于 q2

    小提琴 SQL 服务器

    结论

    测试的 DBMS 都没有成功使用来自约束的信息。

    如果将信息注入查询,则 Db2 是唯一使用该信息的数据库。

    正如它接缝一样,Oracle 是唯一一个对所有 4 个查询都失败的查询。

    • 0

相关问题

  • 我应该如何优化此表的存储?

  • oracle 中的 DBMS_REDEFINITION 与 EXCHANGE PARTITION

  • 将 EXPLAIN 成本转换为(挂钟)运行时是否有好的“经验法则”?

  • RDBMS 上的“索引”是什么意思?[关闭]

  • NoSQL 和传统的 RDBMS 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve