我在多个表上的JOIN查询非常慢

时间:2014-06-08 10:55:03

标签: mysql sql

我目前对高级搜索的查询大约需要60秒才能完成。有什么建议可以改善吗? 数据库:MySQL Web服务器:Apache - PHP(PDO)

当前代码结构:

SELECT  B.title, COUNT(*) AS NUM 
FROM library.PhysicalInfo A 
LEFT JOIN library.BibliographicInfo B 
    ON A.BookID = B.BibliographicInfoID 
LEFT JOIN library.authors C 
    ON B.BibliographicInfoID = C.BookID 
LEFT JOIN library.BookAuthors D 
    ON C.BookAuthorID = D.PersonID 
LEFT JOIN library.series E 
    ON B.BibliographicInfoID = E.BookID 
LEFT JOIN library.BooksLocation F 
    ON A.location = F.BookLocationID 
LEFT JOIN library.PublishStatement G 
    ON B.BibliographicInfoId=G.BookID 
LEFT JOIN library.publisher H 
    ON G.PublisherID = H.PublisherID 
WHERE (     B.title  LIKE '%سلام%' OR 
            D.name LIKE '%سلام%' OR 
            F.location LIKE '%سلام%' OR 
            G.place  LIKE '%سلام%' OR 
            G.year LIKE '%سلام%' OR 
            H.name LIKE '%سلام%' ) 
LIMIT 0, 30

我为连接比较和WHERE语句中使用的所有字段创建了索引:

CREATE INDEX PersonID ON library.BookAuthors(PersonID);
....

我的表结构是:

mysql> DESCRIBE PhysicalInfo;

+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| PhysicalInfoID | int(11)      | NO   | PRI | NULL    | auto_increment |
| volume         | varchar(10)  | YES  |     | NULL    |                |
| section        | varchar(100) | YES  |     | NULL    |                |
| year           | varchar(10)  | YES  |     | NULL    |                |
| RegisterNo     | varchar(20)  | YES  |     | NULL    |                |
| barcode        | varchar(45)  | YES  | MUL | NULL    |                |
| location       | int(11)      | YES  | MUL | NULL    |                |
| BookID         | int(11)      | YES  | MUL | NULL    |                |
| version        | varchar(10)  | YES  |     | NULL    |                |
+----------------+--------------+------+-----+---------+----------------+

mysql> DESCRIBE BibliographicInfo;

+------------------------+---------------+------+-----+---------+----------------+
| Field                  | Type          | Null | Key | Default | Extra |
+------------------------+---------------+------+-----+---------+----------------+
| BibliographicInfoID    | int(11)       | NO   | PRI | NULL    | auto_increment |
| LCNO                   | varchar(45)   | YES  |     | NULL    | |
| DeviNo                 | varchar(45)   | YES  |     | NULL    | |
| title                  | varchar(200)  | YES  | MUL | NULL    | |
| ISBN                   | varchar(20)   | YES  | MUL | NULL    | |
| language               | int(11)       | YES  |     | NULL    | |
| IsReference            | smallint(6)   | YES  |     | NULL    | |
+------------------------+---------------+------+-----+---------+----------------+

EXPLAIN EXTENDED结果:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: A
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 348390
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: B
         type: eq_ref
possible_keys: PRIMARY,BibliographicInfoID
          key: PRIMARY
      key_len: 4
          ref: library.A.BookID
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: C
         type: ref
possible_keys: BookID_idx,BookID
          key: BookID_idx
      key_len: 5
          ref: library.B.BibliographicInfoID
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 4. row ***************************
           id: 1
  select_type: SIMPLE
        table: D
         type: eq_ref
possible_keys: PRIMARY,PersonID
          key: PRIMARY
      key_len: 4
          ref: library.C.BookAuthorID
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 5. row ***************************
           id: 1
  select_type: SIMPLE
        table: E
         type: ref
possible_keys: BookID
          key: BookID
      key_len: 5
          ref: library.B.BibliographicInfoID
         rows: 2
     filtered: 100.00
        Extra: Using index
*************************** 6. row ***************************
           id: 1
  select_type: SIMPLE
        table: F
         type: eq_ref
possible_keys: PRIMARY,BookLocationID
          key: PRIMARY
      key_len: 4
          ref: library.A.location
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 7. row ***************************
           id: 1
  select_type: SIMPLE
        table: G
         type: ref
possible_keys: book_idx,BookID
          key: book_idx
      key_len: 5
          ref: library.B.BibliographicInfoID
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 8. row ***************************
           id: 1
  select_type: SIMPLE
        table: H
         type: eq_ref
possible_keys: PRIMARY,PublisherID
          key: PRIMARY
      key_len: 4
          ref: library.G.PublisherID
         rows: 1
     filtered: 100.00
        Extra: Using where
8 rows in set, 1 warning (0.00 sec)

我当前的查询(大约500万条记录)需要60秒!所以我的问题是:

  1. 我在这做错了什么?
  2. 为什么EXPLAIN EXTENDED中的第一行始终有type=All?据我所知,这是最糟糕的type,不应该存在,因为我已经为该表的BookIDPRIMARY KEY创建了索引。

2 个答案:

答案 0 :(得分:2)

  • 我想到的第一件事是INDEXES。如果您明智地选择它们,它可以显着提高性能。见here
  • 有时你应该考虑展平你的桌子。这样你就可以打破一些规范化的关系数据库规则,但是你可以通过减少"连接"来获得速度。
  • 我有时使用的另一种方式:如果其中一个表没有多个值,您可以在单独的查询中获取它,移动" JOIN"字段到键,(缓存数组)并在查询执行后执行JOIN时获取php(或其他语言)代码中的记录
  • 另一种方法是按时完成一些工作,准备数据并将其插入另一个表,准备提取(由于延迟,在许多用例中不可能)

您始终可以将值存储在缓存中。

答案 1 :(得分:0)

如果您需要从多个表中选择数据,除了在查询中加入它们之外别无选择。

具有多个嵌套级别的查询听起来可能过于复杂,但我建议您是为业务创建解决方案的人,如果您创建了一个复杂的查询,数据中心管理员不会这样做批准当时你应该能够把它带给他们并讨论一个更好的方法。您可能会发现没有比您提供的解决方案更好的方法。

最重要的是,我不相信有人应该能够在不提供帮助的情况下对你施加这样的限制。