0

我知道如果没有 db 表可能很难优化这个查询,但我是一个新手,不会相信自己,这需要很多时间来原谅这个,比如 50 秒,我想不出另一种方法来做到这一点,只是看起来很长

欢迎任何提示以加快速度

SELECT SUM(x) AS d

FROM     ( SELECT COUNT(*) AS x
           FROM ( SELECT DISTINCT id
                  FROM streamsignature
                  WHERE time < '2013-01-03'
                    AND signature = 'v'
                    AND signaturelevel = 'check'
         ) AS subq 

INNER JOIN files             ON subq.id  = files.id 
INNER JOIN filedata fm       ON files.id = fm.id
INNER JOIN filetag v         ON files.id = v.id 
INNER JOIN filetype ft       ON files.id = ft.id

LEFT  JOIN definitiondata dd ON files.id = dd.id

WHERE (    ( NOT filename LIKE '%abc2%' AND filename LIKE '%abc%' )
        OR (     filename LIKE '%abc2%' AND fm.dset = 1           ) )
  AND v.type   BETWEEN 0 and 4
  AND v.length BETWEEN 3 and 7
  AND v.decoder    = 1
  AND v.lighting   = 'bright'
  AND NOT vmd.time = 'xx:xx:Xx'
  AND ft.country   = 'IQ'

UNION

            i have a bunch of them like 4 with different conditions and 
          stuff
4

2 回答 2

2

我对您的查询一无所知,我不知道我是否误解了,但是:

( SELECT COUNT(*) AS x
           FROM ( SELECT DISTINCT id
                  FROM streamsignature
                  WHERE time < '2013-01-03'
                    AND signature = 'v'
                    AND signaturelevel = 'check'
         ) AS subq 

INNER JOIN files             ON subq.id

行数是文件表的 id 吗?就像你一样,在你的 join 子句上有

ON subq.id  = files.id

唯一选择的字段是x,它是行数

反正...

我认为更像是索引问题。您真的应该使用 EXPLAIN 来找出缺少哪些索引。

例如:

EXPLAIN SELECT * FROM orderdetails d
INNER JOIN orders o ON d.orderNumber = o.orderNumber
INNER JOIN products p ON p.productCode = d.productCode
INNER JOIN productlines l ON p.productLine = l.productLine
INNER JOIN customers c on c.customerNumber = o.customerNumber
WHERE o.orderNumber = 10101G

执行该查询将产生:

********************** 1. row **********************
           id: 1
  select_type: SIMPLE
        table: l
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 7
        Extra: 
********************** 2. row **********************
           id: 1
  select_type: SIMPLE
        table: p
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 110
        Extra: Using where; Using join buffer
********************** 3. row **********************
           id: 1
  select_type: SIMPLE
        table: c
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 122
        Extra: Using join buffer
********************** 4. row **********************
           id: 1
  select_type: SIMPLE
        table: o
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 326
        Extra: Using where; Using join buffer
********************** 5. row **********************
           id: 1
  select_type: SIMPLE
        table: d
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2996
        Extra: Using where; Using join buffer
5 rows in set (0.00 sec)`

如果查看上面的结果,您可以看到错误查询的所有症状。但是即使我写了一个更好的查询,结果仍然是一样的,因为没有索引。连接类型显示为“ALL”(这是最差的),这意味着 MySQL 无法识别可以在连接中使用的任何键,因此 possible_keys 和 key 列为空。最重要的是,rows 列显示 MySQL 扫描每个表的所有记录以进行查询。这意味着执行查询时,它将扫描 7 × 110 × 122 × 326 × 2996 = 91,750,822,240 条记录以找到四个匹配的结果。这真的很可怕,而且它只会随着数据库的增长而呈指数级增长。

现在让我们添加一些明显的索引,例如每个表的主键,并再次执行查询。作为一般经验法则,您可以将查询的 JOIN 子句中使用的列视为键的良好候选者,因为 MySQL 将始终扫描这些列以查找匹配的记录。

ALTER TABLE customers
    ADD PRIMARY KEY (customerNumber);
ALTER TABLE employees
    ADD PRIMARY KEY (employeeNumber);
ALTER TABLE offices
    ADD PRIMARY KEY (officeCode);
ALTER TABLE orderdetails
    ADD PRIMARY KEY (orderNumber, productCode);
ALTER TABLE orders
    ADD PRIMARY KEY (orderNumber),
    ADD KEY (customerNumber);
ALTER TABLE payments
    ADD PRIMARY KEY (customerNumber, checkNumber);
ALTER TABLE productlines
    ADD PRIMARY KEY (productLine);
ALTER TABLE products 
    ADD PRIMARY KEY (productCode),
    ADD KEY (buyPrice),
    ADD KEY (productLine);
ALTER TABLE productvariants 
    ADD PRIMARY KEY (variantId),
    ADD KEY (buyPrice),
    ADD KEY (productCode);

添加索引后,让我们再次重新运行相同的查询,结果应如下所示:

********************** 1. row **********************
           id: 1
  select_type: SIMPLE
        table: o
         type: const
possible_keys: PRIMARY,customerNumber
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
********************** 2. row **********************
           id: 1
  select_type: SIMPLE
        table: c
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
********************** 3. row **********************
           id: 1
  select_type: SIMPLE
        table: d
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 4
        Extra: 
********************** 4. row **********************
           id: 1
  select_type: SIMPLE
        table: p
         type: eq_ref
possible_keys: PRIMARY,productLine
          key: PRIMARY
      key_len: 17
          ref: classicmodels.d.productCode
         rows: 1
        Extra: 
********************** 5. row **********************
           id: 1
  select_type: SIMPLE
        table: l
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 52
          ref: classicmodels.p.productLine
         rows: 1
        Extra: 
5 rows in set (0.00 sec)

添加索引后,扫描的记录数减少到了 1 × 1 × 4 × 1 × 1 = 4。这意味着对于 orderdetails 表中每条 orderNumber 10101 的记录,MySQL 能够直接找到所有匹配的记录其他表使用索引,而不必求助于扫描整个表。

于 2013-09-02T22:38:09.957 回答
0

由于问题中没有足够的背景细节,因此很难很好地回答这个问题。但是,查看查询中的一些要点可能会对您有所帮助:

  • 尝试执行更少的连接
  • 避免使用LIKE带有通配符前缀和后缀的查询(即'%thing%')——这将导致全表扫描,如果有大量行,这会削弱性能
  • 尽量避免子选择。它们并不总是一个问题,但它们可能表明以错误的方式处理查询
  • 使用Explain 语法了解您可能缺少重要索引的位置

祝你好运!

于 2013-09-02T21:03:19.410 回答