mysql - 慢sql查询优化,

标签 mysql sql

我知道在没有数据库表的情况下可能很难优化这个查询,但我是一个新手,不会相信自己,需要花很多时间来原谅这个问题,比如 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

最佳答案

我不明白你的问题,我不知道我是否理解错误,但是:

( 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 和键列为空。最重要的是,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 都能直接找到匹配的记录使用索引记录在所有其他表中,而不必扫描整个表。

关于mysql - 慢sql查询优化,,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18580594/

相关文章:

sql - PostgreSQL 单列索引与多列索引以获得最佳 SELECT 性能

c++ - 在 C++ 中通过 SSL 进行简单的数据库连接

sql - PostgreSQL 数据库模型

php - 使用MySQL在插入时生成半随机字符串

mysql查询从三个表中选择数据

mysql - 使用变量选择和更新

php - 使用 php 将数据插入 pdf?

java - SQL Server 2014 的 JDBC 驱动程序

Mysql通过加入另一个表来更新表

java - 使用registerOutParameter函数时将oracle的 "OracleTypes.CURSOR"替换为mysql中的等效值