Op 7 mrt 2015, om 19:24 heeft Wolfgang Enzinger het volgende geschreven:

> Hi dev team,
>
> not sure if this is actually a useful hint, but ...
>
> CREATE TABLE a(a1 INTEGER PRIMARY KEY);
> INSERT INTO a VALUES (1),(2),(3);
> CREATE TABLE b(a1 INTEGER REFERENCES a(a1),b1 INTEGER PRIMARY KEY);
> INSERT INTO b VALUES (1,11),(2,22),(3,33);
> CREATE UNIQUE INDEX b_ui ON b(a1,b1);
> CREATE TABLE c(b1 INTEGER REFERENCES b(b1),c1 INTEGER PRIMARY KEY,c2  
> TEXT);
> INSERT INTO c VALUES (11,111,'a'),(22,222,'b'),(33,333,'c');
> CREATE UNIQUE INDEX c_ui ON c(b1,c1);
> ANALYZE;
>
> Query 1:
>
> EXPLAIN QUERY PLAN
> SELECT a1 FROM a WHERE EXISTS(SELECT * FROM b INNER JOIN c USING(b1)  
> WHERE
> b.a1=a.a1 AND c.c1=222);
>
> selectid      order   from    detail
> 0     0       0       SCAN TABLE a
> 0     0       0       EXECUTE CORRELATED SCALAR SUBQUERY 1
> 1     0       1       SEARCH TABLE c USING INTEGER PRIMARY KEY (rowid=?)
> 1     1       0       SEARCH TABLE b USING INTEGER PRIMARY KEY (rowid=?)
>
> Query 2:
>
> EXPLAIN QUERY PLAN
> SELECT a1 FROM a WHERE EXISTS(SELECT c1 FROM b INNER JOIN c  
> USING(b1) WHERE
> b.a1=a.a1 AND c.c1=222);
>
> selectid      order   from    detail
> 0     0       0       SCAN TABLE a
> 0     0       0       EXECUTE CORRELATED SCALAR SUBQUERY 1
> 1     0       0       SEARCH TABLE b USING COVERING INDEX b_ui (a1=?)
> 1     1       1       SEARCH TABLE c USING COVERING INDEX c_ui (b1=?)
>
> Note that the only difference between the two is "SELECT *" vs.  
> "SELECT c1"
> within the EXISTS-block. The result is the same in both cases,  
> however the
> second query uses COVERING INDEXes which should be more efficient  
> (as far
> as I know).
>
> HTH; and sorry for the noise if not.
>
> Wolfgang
Hello, as yiou gave a very clear example of the case, I dare to reply.

Actually query one appears slightly faster,
Searching the PK index is faster as that is always a COVERING index.
 From the secunsary indexes only a part oh the key is used.
Note there is not much use on adding PK as second column in the  
additional indexes. It is there anyway a a pointer to the row.

I agree that it is strange that the execution plan for the two queries  
is different, After EXISTS the optimizer might ignore the expression  
in the select part of the sub-query. And Query one looks better as it  
soes not mention any column names. Personally I'd write SELECT NULL  
instead of SELECT *.

If speed matters instead of EXIST you can use IN and a list sub-query.  
This is superfast now:

SELECT a1 FROM a WHERE a1 in (SELECT b.a1 FROM b INNER JOIN c  
USING(b1) WHERE c.c1=222);

0|0|0|SEARCH TABLE a USING INTEGER PRIMARY KEY (rowid=?)
0|0|0|EXECUTE LIST SUBQUERY 1
1|0|1|SEARCH TABLE c USING INTEGER PRIMARY KEY (rowid=?)
1|1|0|SEARCH TABLE b USING INTEGER PRIMARY KEY (rowid=?)

Edzard Pasma

Reply via email to