索引和优化

Rwd*_*Rwd 5 mysql sql

当谈到超越MySQL的基础时,我并不精彩,但是,我正在尝试优化查询:

SELECT DATE_FORMAT(t.completed, '%H') AS hour, t.orderId, t.completed as stamp,
       t.deadline as deadline, t.completedBy as user, p.largeFormat as largeFormat 
    FROM tasks t
    JOIN orders o ON o.id=t.orderId
    JOIN products p ON p.id=o.productId
    WHERE DATE(t.completed) = '2013-09-11'
    AND t.type = 7
    AND t.completedBy IN ('user1', 'user2')
    AND t.suspended = '0'
    AND o.shanleys = 0
    LIMIT 0,100

+----+-------------+-------+--------+----------------------------+-----------+---------+-----------------+-------+-------------+
| id | select_type | table | type   | possible_keys              | key       | key_len | ref             | rows  | Extra       |
+----+-------------+-------+--------+----------------------------+-----------+---------+-----------------+-------+-------------+
|  1 | SIMPLE      | o     | ref    | PRIMARY,productId,shanleys | shanleys  | 2       | const           | 54464 | Using where |
|  1 | SIMPLE      | p     | eq_ref | PRIMARY                    | PRIMARY   | 4       | sfp.o.productId |     1 |             |
|  1 | SIMPLE      | t     | ref    | NewIndex1                  | NewIndex1 | 5       | sfp.o.id        |     6 | Using where |
+----+-------------+-------+--------+----------------------------+-----------+---------+-----------------+-------+-------------+
Run Code Online (Sandbox Code Playgroud)

在添加一些索引之前,它在p表和o表上执行全表扫描.

基本上,我认为MySQL会:

使用where子句限制任务表中的行(应该是没有连接的84行)

然后通过orders表到products表获取一个flag(largeFormat).

我的问题是为什么当MySQL只有84个不同的ID要查找时,它会查找50000多行,有没有办法可以优化查询?

我无法添加新字段或新表.

先感谢您!

DRa*_*app 5

SQL需要处理可用索引以最好地限定查询

我会有一个复合索引(类型,暂停,已完成,已完成)以匹配您的标准...您的订单和产品表与现有索引一起显示正常.

SELECT 
      DATE_FORMAT(t.completed, '%H') AS hour, 
      t.orderId, 
      t.completed as stamp,
      t.deadline, 
      t.completedBy as user, 
      p.largeFormat as largeFormat 
   FROM 
      tasks t
         JOIN orders o 
            ON t.orderId = o.id
           AND o.shanleys = 0
            JOIN products p 
               ON o.productId = p.id
   WHERE 
          t.type = 7
      AND t.suspended = 0
      AND t.completedBy IN ('user1', 'user2')
      AND t.completed >= '2013-09-11'
      AND t.completed < '2013-09-12'
   LIMIT 
      0,100
Run Code Online (Sandbox Code Playgroud)

我怀疑suspended是一个标志并且是基于数字(int)的,如果是这样的话,请将条件保留为数字而不是字符串,方法是用'0'引号括起来.

对于日期时间字段,如果您尝试将函数应用于它,它无法很好地利用索引...所以,如果您只关心一天(或其他查询中的范围),请注意我有datetime字段> ='2013 -09-11'暗示上午12:00:00,且datetime字段少于'2013-09-12',允许在2013-09-11的最后11:59:59 PM这是整个一天和索引可以利用它.

  • @RossWilson,欢迎你,我经常尝试为我的答案提供帮助,以帮助其他人学习为什么,并可以在将来可能出现的查询问题中应用这样的推理.您可以通过点击它们并搜索它们的标签(例如[mysql])或其他任何内容来查看任何人的问题历史...也许已经提供的其他答案可能会帮助您在需要提出之前解决 - 而不是询问始终是坏事. (2认同)
  • +1 DRapp .. @RossWilson,当涉及范围时,您应该始终首先索引相等性,这允许 MySQL 使用索引中的更多部分(是什么使索引更具选择性,请查看此查询的解释中的 key_len,这可能更大现在编号)。&gt;= 的范围扫描只能使用最左边的前缀列来过滤掉不匹配的记录。 (2认同)