为什么我的索引不能用于带有连接的大型查询?

时间:2014-04-29 06:23:06

标签: sql sqlite

我有一个名为street_names的表格:

CREATE TABLE street_names (
            id INTEGER PRIMARY KEY NOT NULL,
            name TEXT UNIQUE NOT NULL
          );

使用LIKE搜索时,它会使用索引并立即返回结果。但是,请采用这个更大的表达式:

SELECT sn.name, sa.house_number, sa.entrance, pc.postal_code, ci.name, mu.name,
       co.name, sa.latitude, sa.longitude
FROM
  street_addresses AS sa
  INNER JOIN street_names   AS sn ON sa.street_name  = sn.id
  INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id
  INNER JOIN cities         AS ci ON sa.city         = ci.id
  INNER JOIN municipalities AS mu ON sa.municipality = mu.id
  INNER JOIN counties       AS co ON mu.county       = co.id
WHERE
  sn.name = "FORNEBUVEIEN" AND
  sa.house_number = 13
ORDER BY ci.name ASC, sn.name ASC, sa.house_number ASC, sa.entrance ASC
LIMIT 0, 100;

在当前状态下,它的闪电速度非常快,并且可以在我的机器上每秒运行6000次,但只要我将街道名称上的=更改为LIKE:< / p>

SELECT sn.name, sa.house_number, sa.entrance, pc.postal_code, ci.name, mu.name,
       co.name, sa.latitude, sa.longitude
FROM
  street_addresses AS sa
  INNER JOIN street_names   AS sn ON sa.street_name  = sn.id
  INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id
  INNER JOIN cities         AS ci ON sa.city         = ci.id
  INNER JOIN municipalities AS mu ON sa.municipality = mu.id
  INNER JOIN counties       AS co ON mu.county       = co.id
WHERE
  sn.name LIKE "FORNEBUVEIEN" AND
  sa.house_number = 13
ORDER BY ci.name ASC, sn.name ASC, sa.house_number ASC, sa.entrance ASC
LIMIT 0, 100;

它变坏了,在我的机器上每秒运行10次。为什么是这样?我所做的唯一更改是将索引列上的=更改为LIKE,并且查询甚至不包含任何通配符。


表模式:

CREATE TABLE street_addresses (
            id INTEGER PRIMARY KEY NOT NULL,
            house_number INTEGER NOT NULL,
            entrance TEXT NOT NULL,
            latitude REAL NOT NULL,
            longitude REAL NOT NULL,
            street_name INTEGER NOT NULL REFERENCES street_names(id),
            postal_code INTEGER NOT NULL REFERENCES postal_codes(id),
            city INTEGER NOT NULL REFERENCES cities(id),
            municipality INTEGER NOT NULL REFERENCES municipalities(id),
            CONSTRAINT unique_address UNIQUE(
              street_name, house_number, entrance, postal_code, city
            )
          );

CREATE TABLE street_names (
            id INTEGER PRIMARY KEY NOT NULL,
            name TEXT UNIQUE NOT NULL
          );

CREATE TABLE postal_codes (
            id INTEGER PRIMARY KEY NOT NULL,
            postal_code INTEGER NOT NULL,
            city INTEGER NOT NULL REFERENCES cities(id),
            CONSTRAINT unique_postal_code UNIQUE(postal_code, city)
          );

CREATE TABLE cities (
            id INTEGER PRIMARY KEY NOT NULL,
            name TEXT NOT NULL,
            municipality INTEGER NOT NULL REFERENCES municipalities(id),
            CONSTRAINT unique_city UNIQUE(name, municipality)
          );

CREATE TABLE municipalities (
            id INTEGER PRIMARY KEY NOT NULL,
            name TEXT NOT NULL,
            NUMBER INTEGER UNIQUE NOT NULL,
            county INTEGER NOT NULL REFERENCES counties(id),
            CONSTRAINT unique_municipality UNIQUE(name, county)
          );

CREATE TABLE counties (
            id INTEGER PRIMARY KEY NOT NULL,
            name TEXT UNIQUE NOT NULL
          );

EXPLAIN查询... sn.name = ...

sqlite> EXPLAIN SELECT sn.name, sa.house_number, sa.entrance, pc.postal_code, ci.name, mu.name, co.name, sa.latitude, sa.longitude FROM street_addresses AS sa INNER JOIN street_names   AS sn ON sa.street_name  = sn.id INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id INNER JOIN cities         AS ci ON sa.city         = ci.id INNER JOIN municipalities AS mu ON sa.municipality = mu.id INNER JOIN counties       AS co ON mu.county       = co.id WHERE sn.name = "FORNEBUVEIEN" AND sa.house_number = 13 ORDER BY ci.name ASC, sn.name ASC, sa.house_number ASC, sa.entrance ASC LIMIT 0, 100; 
addr        opcode      p1          p2          p3          p4          p5          comment   
----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------
0           Init        0           91          0                       00                    
1           OpenEpheme  6           6           0           k(4,B,B,B,  00                    
2           Integer     100         1           0                       00                    
3           Integer     0           2           0                       00                    
4           MustBeInt   2           0           0                       00                    
5           IfPos       2           7           0                       00                    
6           Integer     0           2           0                       00                    
7           Add         1           2           3                       00                    
8           IfPos       1           10          0                       00                    
9           Integer     -1          3           0                       00                    
10          OpenRead    7           12          0           k(2,nil,ni  00                    
11          OpenRead    0           13          0           9           00                    
12          OpenRead    8           14          0           k(5,nil,ni  00                    
13          OpenRead    2           9           0           2           00                    
14          OpenRead    3           7           0           2           00                    
15          OpenRead    4           4           0           4           00                    
16          OpenRead    5           2           0           2           00                    
17          String8     0           4           0           FORNEBUVEI  00                    
18          SeekGE      7           65          4           1           00                    
19          IdxGT       7           65          4           1           00                    
20          IdxRowid    7           5           0                       00                    
21          IsNull      5           65          0                       00                    
22          Integer     13          6           0                       00                    
23          SeekGE      8           65          5           2           00                    
24          IdxGT       8           65          5           2           00                    
25          IdxRowid    8           7           0                       00                    
26          Seek        0           7           0                       00                    
27          Column      8           3           8                       00                    
28          MustBeInt   8           64          0                       00                    
29          NotExists   2           64          8                       00                    
30          Column      8           4           9                       00                    
31          MustBeInt   9           64          0                       00                    
32          NotExists   3           64          9                       00                    
33          Column      0           8           10                      00                    
34          MustBeInt   10          64          0                       00                    
35          NotExists   4           64          10                      00                    
36          Column      4           3           11                      00                    
37          MustBeInt   11          64          0                       00                    
38          NotExists   5           64          11                      00                    
39          Column      7           0           12                      00                    
40          Column      8           1           13                      00                    
41          Column      8           2           14                      00                    
42          Column      2           1           15                      00                    
43          Column      3           1           16                      00                    
44          Column      4           1           17                      00                    
45          Column      5           1           18                      00                    
46          Column      0           3           19                      00                    
47          RealAffini  19          0           0                       00                    
48          Column      0           4           20                      00                    
49          RealAffini  20          0           0                       00                    
50          MakeRecord  12          9           21                      00                    
51          Column      3           1           22                      00                    
52          Column      7           0           23                      00                    
53          Column      8           1           24                      00                    
54          Column      8           2           25                      00                    
55          Sequence    6           26          0                       00                    
56          Move        21          27          0                       00                    
57          MakeRecord  22          6           28                      00                    
58          IdxInsert   6           28          0                       00                    
59          IfZero      3           62          0                       00                    
60          AddImm      3           -1          0                       00                    
61          Goto        0           64          0                       00                    
62          Last        6           0           0                       00                    
63          Delete      6           0           0                       00                    
64          Next        8           24          0                       00                    
65          Close       7           0           0                       00                    
66          Close       0           0           0                       00                    
67          Close       8           0           0                       00                    
68          Close       2           0           0                       00                    
69          Close       3           0           0                       00                    
70          Close       4           0           0                       00                    
71          Close       5           0           0                       00                    
72          OpenPseudo  9           21          9                       00                    
73          Sort        6           89          0                       00                    
74          AddImm      2           -1          0                       00                    
75          IfNeg       2           77          0                       00                    
76          Goto        0           88          0                       00                    
77          Column      6           5           21                      00                    
78          Column      9           0           12                      20                    
79          Column      9           1           13                      00                    
80          Column      9           2           14                      00                    
81          Column      9           3           15                      00                    
82          Column      9           4           16                      00                    
83          Column      9           5           17                      00                    
84          Column      9           6           18                      00                    
85          Column      9           7           19                      00                    
86          Column      9           8           20                      00                    
87          ResultRow   12          9           0                       00                    
88          Next        6           74          0                       00                    
89          Close       9           0           0                       00                    
90          Halt        0           0           0                       00                    
91          Transactio  0           0           10          0           01                    
92          TableLock   0           11          0           street_nam  00                    
93          TableLock   0           13          0           street_add  00                    
94          TableLock   0           9           0           postal_cod  00                    
95          TableLock   0           7           0           cities      00                    
96          TableLock   0           4           0           municipali  00                    
97          TableLock   0           2           0           counties    00                    
98          Goto        0           1           0                       00

EXPLAIN查询... sn.name LIKE ...

sqlite> EXPLAIN SELECT sn.name, sa.house_number, sa.entrance, pc.postal_code, ci.name, mu.name, co.name, sa.latitude, sa.longitude FROM street_addresses AS sa INNER JOIN street_names   AS sn ON sa.street_name  = sn.id INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id INNER JOIN cities         AS ci ON sa.city         = ci.id INNER JOIN municipalities AS mu ON sa.municipality = mu.id INNER JOIN counties       AS co ON mu.county       = co.id WHERE sn.name LIKE "FORNEBUVEIEN" AND sa.house_number = 13 ORDER BY ci.name ASC, sn.name ASC, sa.house_number ASC, sa.entrance ASC LIMIT 0, 100; 
addr        opcode      p1          p2          p3          p4          p5          comment   
----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------
0           Init        0           88          0                       00                    
1           OpenEpheme  6           6           0           k(4,B,B,B,  00                    
2           Integer     100         1           0                       00                    
3           Integer     0           2           0                       00                    
4           MustBeInt   2           0           0                       00                    
5           IfPos       2           7           0                       00                    
6           Integer     0           2           0                       00                    
7           Add         1           2           3                       00                    
8           IfPos       1           10          0                       00                    
9           Integer     -1          3           0                       00                    
10          OpenRead    0           13          0           9           00                    
11          OpenRead    1           11          0           2           00                    
12          OpenRead    4           4           0           4           00                    
13          OpenRead    3           7           0           2           00                    
14          OpenRead    5           2           0           2           00                    
15          OpenRead    2           9           0           2           00                    
16          Rewind      0           63          0                       00                    
17          Column      0           1           4                       00                    
18          Ne          5           62          4           (BINARY)    6c                    
19          Column      0           5           6                       00                    
20          MustBeInt   6           62          0                       00                    
21          NotExists   1           62          6                       00                    
22          Column      1           1           9                       00                    
23          Function    1           8           7           like(2)     02                    
24          IfNot       7           62          1                       00                    
25          Column      0           8           10                      00                    
26          MustBeInt   10          62          0                       00                    
27          NotExists   4           62          10                      00                    
28          Column      0           7           11                      00                    
29          MustBeInt   11          62          0                       00                    
30          NotExists   3           62          11                      00                    
31          Column      4           3           12                      00                    
32          MustBeInt   12          62          0                       00                    
33          NotExists   5           62          12                      00                    
34          Column      0           6           13                      00                    
35          MustBeInt   13          62          0                       00                    
36          NotExists   2           62          13                      00                    
37          Column      1           1           14                      00                    
38          Copy        4           15          0                       00                    
39          Column      0           2           16                      00                    
40          Column      2           1           17                      00                    
41          Column      3           1           18                      00                    
42          Column      4           1           19                      00                    
43          Column      5           1           20                      00                    
44          Column      0           3           21                      00                    
45          RealAffini  21          0           0                       00                    
46          Column      0           4           22                      00                    
47          RealAffini  22          0           0                       00                    
48          MakeRecord  14          9           7                       00                    
49          Column      3           1           23                      00                    
50          Column      1           1           24                      00                    
51          Column      0           1           25                      00                    
52          Column      0           2           26                      00                    
53          Sequence    6           27          0                       00                    
54          Move        7           28          0                       00                    
55          MakeRecord  23          6           29                      00                    
56          IdxInsert   6           29          0                       00                    
57          IfZero      3           60          0                       00                    
58          AddImm      3           -1          0                       00                    
59          Goto        0           62          0                       00                    
60          Last        6           0           0                       00                    
61          Delete      6           0           0                       00                    
62          Next        0           17          0                       01                    
63          Close       0           0           0                       00                    
64          Close       1           0           0                       00                    
65          Close       4           0           0                       00                    
66          Close       3           0           0                       00                    
67          Close       5           0           0                       00                    
68          Close       2           0           0                       00                    
69          OpenPseudo  7           7           9                       00                    
70          Sort        6           86          0                       00                    
71          AddImm      2           -1          0                       00                    
72          IfNeg       2           74          0                       00                    
73          Goto        0           85          0                       00                    
74          Column      6           5           7                       00                    
75          Column      7           0           14                      20                    
76          Column      7           1           15                      00                    
77          Column      7           2           16                      00                    
78          Column      7           3           17                      00                    
79          Column      7           4           18                      00                    
80          Column      7           5           19                      00                    
81          Column      7           6           20                      00                    
82          Column      7           7           21                      00                    
83          Column      7           8           22                      00                    
84          ResultRow   14          9           0                       00                    
85          Next        6           71          0                       00                    
86          Close       7           0           0                       00                    
87          Halt        0           0           0                       00                    
88          Transactio  0           0           10          0           01                    
89          TableLock   0           13          0           street_add  00                    
90          TableLock   0           11          0           street_nam  00                    
91          TableLock   0           4           0           municipali  00                    
92          TableLock   0           7           0           cities      00                    
93          TableLock   0           2           0           counties    00                    
94          TableLock   0           9           0           postal_cod  00                    
95          Integer     13          5           0                       00                    
96          String8     0           8           0           FORNEBUVEI  00                    
97          Goto        0           1           0                       00

2 个答案:

答案 0 :(得分:3)

documentation表示LIKE需要不区分大小写的索引:

CREATE INDEX ci_name ON street_names(name COLLATE NOCASE);
EXPLAIN QUERY PLAN SELECT ... sn.name LIKE "FORNEBUVEIEN" ...;
0|0|1|SEARCH TABLE street_names AS sn USING COVERING INDEX ci_name (name>? AND name<?)
...

或者,使用GLOB可以使用区分大小写的索引:

EXPLAIN QUERY PLAN SELECT ... sn.name GLOB "FORNEBUVEIEN" ...;
0|0|1|SEARCH TABLE street_names AS sn USING COVERING INDEX sqlite_autoindex_street_names_1 (name>? AND name<?)
...

答案 1 :(得分:0)

我不是一个sqlite专家,但在任何SQL方言中,LIKE永远不会像=一样快。但也许您可以重新排列查询以优化它:

SELECT sn.name, sa.house_number, sa.entrance, pc.postal_code, ci.name, mu.name,
       co.name, sa.latitude, sa.longitude
FROM
  street_addresses AS sa
  INNER JOIN street_names   AS sn ON sa.street_name  = sn.id
  AND sn.name LIKE "FORNEBUVEIEN"
  INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id
  AND sa.house_number = 13
  INNER JOIN cities         AS ci ON sa.city         = ci.id
  INNER JOIN municipalities AS mu ON sa.municipality = mu.id
  INNER JOIN counties       AS co ON mu.county       = co.id
ORDER BY ci.name ASC, sn.name ASC, sa.house_number ASC, sa.entrance ASC
LIMIT 0, 100;

我的想法是,通过尽早强制进行评估,可以解析更少的数据。当然,如果优化器足够智能,它就已经优化了访问路径。