【问题标题】:which query is optimal id<>3 or id in {1,2,4}哪个查询是最佳 id<>3 或 {1,2,4} 中的 id
【发布时间】:2015-06-26 18:09:32
【问题描述】:

如果一个表有很多行,每行有很多列,哪个查询更快?

如果列的值在 {1,2,3,4} 内

    SELECT * FROM table t WHERE t.column1<>3

或者

    SELECT * FROM table t WHERE t.column1 in {1,2,4}

这两种情况下是 3 次比较还是 1 次比较?

【问题讨论】:

  • 这是用于 mysql、oracle 还是 sql server 的?请只标记合适的产品
  • 我想知道每个人
  • 'in' 需要更多时间,而且在查询中使用运算符而不是单词会更快..
  • @DevLakshman:id IN(1,2,3)id=1 OR id=2 OR id=3 的替代品。 @user4002899:在我看来,对于有限数量的值,第二种方法应该更快
  • 是的..而不是 'in' , 'OR' 更快

标签: mysql sql sql-server oracle


【解决方案1】:

在 sqlserver 2008 和 2012 上测试:

问题N 3中的第一种方法:

CREATE TABLE #t (n INT)

;WITH N1 (N) AS 
(SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
N4 (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N1.N) FROM N3 AS N1 CROSS JOIN N3 AS N2),
N5 (N) AS (SELECT top 50000000 N%4 + 1 N FROM n4)
INSERT #t
SELECT n from n5

DECLARE @dummy int

DECLARE @a datetime = getdate()
SELECT @dummy = count(*)
FROM #t
WHERE N <> 3

SELECT datediff(ms, 0, getdate() - @a)

结果:

3886 milliseconds    

问题的第二种方法

CREATE TABLE #t (n INT)

;WITH N1 (N) AS 
(SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1),
(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
N4 (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N1.N) FROM N3 AS N1 CROSS JOIN N3 AS N2),
N5 (N) AS (SELECT top 50000000 N%4 + 1 N FROM n4)
INSERT #t
SELECT n from n5

DECLARE @dummy int

DECLARE @a datetime = getdate()
SELECT @dummy = count(*) 
FROM #t
WHERE N in (1,2,4)

SELECT datediff(ms, 0, getdate() - @a)

结果:

4223 milliseconds

结论

N 3 更快(3886 vs 4223 毫秒)

是的,这似乎是一个很小的差异,但如果该列被声明为 varchar(10) - CREATE TABLE #t (n INT) - 差异会更显着(经过测试)。

【讨论】:

    【解决方案2】:

    它们是不同的。第一个选择 ID 不为 3 的所有记录,而第二个选择所有 ID 为 1、2 或 4 的记录。例如,不包括 ID = 5 的记录。

    因此性能不应该是选择一个查询而不是另一个的原因。 要么您在此表中有数百万条记录,然后IN 方法不起作用,或者您实际上只有这 4 条记录,那么您在问什么?在可读性和故障安全方面选择最合适的方式,不要关心纳秒。

    查询优化主要依赖于 RDBMS,那么您使用的是哪个?在 SQL-Server 中应该没有区别。但是你自己检查一下。 If you have two horses and you want to know which of the two is the faster then race your horses.

    【讨论】:

    • 如果表中id的值在{1,2,3,4}中
    • @user4002899:即使今天表中只有那4条记录,你怎么知道总是这样?不要编写将来可能会失败的查询。
    • @user4002899:查询优化主要依赖于关系型数据库,那么您使用的是哪个?在 SQL-Server 中没有区别(imo)。但是你自己去看看。
    • 你确定在 sql server 中没有差异,如果是 oracle??
    • @user4002899:你想优化什么?这根本没有多大意义。由于要么您在此表中有数百万条记录,那么 IN 方法不起作用,或者您实际上只有这 4 条记录,那么您在问什么,如果数据库需要用一种方法再多一纳秒?在可读性和故障安全方面选择最合适的方式,不要关心纳秒。
    【解决方案3】:

    在 Oracle 中,如果您有 INDEX,将会产生巨大的影响。你可以做一个小测试用例,检查每条语句的解释计划。

    • 案例#1:没有索引

    设置

    出于演示目的,我从 scott.emp 表中创建了一个小表,有 4 行。

    SQL> CREATE TABLE t AS SELECT * FROM emp WHERE empno IN (7369, 7499, 7521, 7566);
    
    Table created.
    
    SQL>
    

    由于我在 12c,CTAS 不需要收集统计数据。

    让我们看看解释计划:

    使用不等于条件

    SQL> EXPLAIN PLAN FOR SELECT * FROM t WHERE empno <> 7369;
    
    Explained.
    
    SQL>
    SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------
    Plan hash value: 1601196873
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     3 |   117 |     3   (0)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| T    |     3 |   117 |     3   (0)| 00:00:01 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("EMPNO"<>7369)
    
    13 rows selected.
    
    SQL>
    

    使用 IN 条件

    SQL> EXPLAIN PLAN FOR SELECT * FROM t WHERE empno IN (7499, 7521, 7566);
    
    Explained.
    
    SQL>
    SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
    
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------
    Plan hash value: 1601196873
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     3 |   117 |     3   (0)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| T    |     3 |   117 |     3   (0)| 00:00:01 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("EMPNO"=7499 OR "EMPNO"=7521 OR "EMPNO"=7566)
    
    13 rows selected.
    
    SQL>
    
    • 案例#2:有索引

    设置

    SQL> CREATE INDEX t_indx ON t(empno);
    
    Index created.
    
    SQL>
    

    使用不等于条件

    SQL> EXPLAIN PLAN FOR SELECT * FROM t WHERE empno <> 7369;
    
    Explained.
    
    SQL>
    SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
    
    PLAN_TABLE_OUTPUT
    -----------------------------------------------------------------------------------------------
    Plan hash value: 1601196873
    
    --------------------------------------------------------------------------
    | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------
    |   0 | SELECT STATEMENT  |      |     3 |   117 |     3   (0)| 00:00:01 |
    |*  1 |  TABLE ACCESS FULL| T    |     3 |   117 |     3   (0)| 00:00:01 |
    --------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("EMPNO"<>7369)
    
    13 rows selected.
    
    SQL>
    

    使用 IN 条件

    SQL> EXPLAIN PLAN FOR SELECT * FROM t WHERE empno IN (7499, 7521, 7566);
    
    Explained.
    
    SQL>
    SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
    
    PLAN_TABLE_OUTPUT
    -----------------------------------------------------------------------------------------------
    Plan hash value: 4217410154
    
    -----------------------------------------------------------------------------------------------
    | Id  | Operation                            | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                     |        |     3 |   117 |     2   (0)| 00:00:01 |
    |   1 |  INLIST ITERATOR                     |        |       |       |            |          |
    |   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T      |     3 |   117 |     2   (0)| 00:00:01 |
    |*  3 |    INDEX RANGE SCAN                  | T_INDX |     3 |       |     1   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       3 - access("EMPNO"=7499 OR "EMPNO"=7521 OR "EMPNO"=7566)
    
    15 rows selected.
    
    SQL>
    

    【讨论】:

    • 那么你的结论是什么?哪个更快?
    • 有了这么少的数据集,优化器对几乎所有的情况都有一个最优的计划。因此,这将完全取决于索引的基数和选择性。 OP 可以在他的环境中对其进行测试。根据我的测试用例无法得出结论。而且我的测试用例仅与 Oracle 有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    • 2020-07-29
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多