0

我有以下超级慢的查询(仅需要 4-5 秒才能得到结果。我想知道是否有人可以看到我可以用这个查询做不同的事情来加快它的速度?

谢谢!

SELECT
accounts.id AS account_id,
accounts. NAME AS account_name,
accounts.assigned_user_id account_id_owner,
users.user_name AS assigned_user_name,
opportunities_cstm.firstname_c, opportunities_cstm.lastname_c,
opportunities.`name`, TRIM(
    Concat(
        Ifnull(
            opportunities_cstm.firstname_c,
            ''
        ),
        ' ',
        Ifnull(
            opportunities_cstm.lastname_c,
            ''
        )
    )
) AS 'cfull' FROM
opportunities 
LEFT JOIN users ON opportunities.assigned_user_id = users.id 
LEFT JOIN accounts_opportunities ON opportunities.id = accounts_opportunities.opportunity_id 
LEFT JOIN accounts ON accounts_opportunities.account_id = accounts.id
LEFT JOIN opportunities_cstm ON opportunities.id = opportunities_cstm.id_c
WHERE
(
    (
        opportunities.sales_stage IN (
            'Prospecting',
            'Appointment Set',
            'MeetAndGreet',
            'Qualification',
            'Needs Analysis',
            'Locating Vehicle',
            'Demo',
            'Trade Evaluation',
            'Negotiation',
            'Manager T/O',
            'Write Up',
            'Credit App Submitted',
            'Pending Finance',
            'Loan Approval',
            'Deposit',
            'Delayed Decision',
            'Sold-Vehicle Ordered',
            'Sold-Pending Finance',
            'Sold/Pending Delivery',
            'Price Quoted',
            'Service Pending'
        )
    )
)
AND (
accounts_opportunities.deleted IS NULL
OR accounts_opportunities.deleted = 0
)
AND (
accounts.deleted IS NULL
OR accounts.deleted = 0
)
AND opportunities.deleted = 0
ORDER BY
opportunities.date_entered DESC,
opportunities.id DESC
LIMIT 0,21

这是来自同一查询的解释:

╔═════════════╦════════════════════════╦════════╦═ ═════════════════════════╦═════════════════════╦══ ═══════╦══════════════════════════════════════════ ══╦═══════╦═════════════════════════════╗
║ select_type ║ table ║ type ║ possible_keys ║ key ║ key_len ║ ref ║ rows ║ extra ║
╠═════════════╬════════════════════════╬════════╬═ ═════════════════════════╬═════════════════════╬══ ═══════╬══════════════════════════════════════════ ══╬═══════╬══════════════════════════════
║ 简单 ║ 机会 ║ 范围 ║ sales_stage, idx_deleted ║ sales_stage ║ 78 ║ null ║ 25161 ║ 使用where;使用文件排序║
║ 简单 ║ 用户 ║ eq_ref ║ PRIMARY, idx_id_deleted ║ PRIMARY ║ 108 ║ version4.opportunities.assigned_user_id ║ 1 ║ ║
║ simple ║ accounts_opportunities ║ ref ║ idx_oppid_del_accid ║ idx_oppid_del_accid ║ 111 ║ version4.opportunities.id ║ 1 ║ 使用 where;使用索引║
║ 简单 ║ 账户 ║ eq_ref ║ PRIMARY,idx_accnt_id_del ║ PRIMARY ║ 108 ║ version4.accounts_opportunities.account_id ║ 1 ║ 使用where ║
║ 简单 ║ 机会_cstm ║ eq_ref ║ 初级 ║ 初级 ║ 108 ║ version4.opportunities.id ║ 1 ║ ║
╚═════════════╩════════════════════════╩════════╩═ ═════════════════════════╩═════════════════════╩══ ═══════╩══════════════════════════════════════════ ══╩═══════╩═════════════════════════════╝
4

3 回答 3

1

我看到两个问题。

首先,您使用了两个不同的WHERE (... IS NULL OR ... = 0)标准。那些慢得无法形容。这是因为索引对于查找 NULL 值没有用。如果您可以摆脱这些deleted列中 NULL 的可能性,也许通过声明它们,NOT NULL DEFAULT 0您可以将这些条件更改为WHERE ... = 0. 这应该加快很多事情。这是因为索引对于查找 NULL 值没有用。

其次,您正在创建一个很棒的大合并结果集,然后对其进行排序以查找最新项目。

在加入之前,您可以尝试从“机会”表中预先选择项目。做这样的事情:

SELECT   whatever....
FROM (
         SELECT * 
           FROM opportunities
          WHERE opportunities.deleted = 0
            AND opportunities.sales_stage IN (
            'Prospecting',
            'Appointment Set',  etc etc  ...
            'Service Pending' )
       ORDER BY opportunities.date_entered DESC,
                opportunities.id DESC
          LIMIT 0,21
      ) opportunities 
LEFT JOIN users ON opportunities.assigned_user_id = users.id
...
ORDER BY
opportunities.date_entered DESC,
opportunities.id DESC
LIMIT 0,21

这很可能可以通过从联接的右侧删除一堆记录来减少 LEFT JOIN 操作的基数来加快速度。

于 2012-11-19T23:01:01.163 回答
0

我不确定它会有所改善,但我会尝试的是:

SELECT your_fields
FROM
  (SELECT * --or just the fields you need
   FROM
     opportunities
   WHERE
     opportunities.deleted = 0 AND
     opportunities.sales_stage IN (stage1, stage2, ...)
  ) opportunities1
  LEFT JOIN users ON opportunities1.assigned_user_id = users.id 
  LEFT JOIN accounts_opportunities ON opportunities1.id = ...etc...
WHERE
  (accounts_opportunities.deleted IS NULL
   OR accounts_opportunities.deleted = 0)
  AND (accounts.deleted IS NULL OR accounts.deleted = 0)
ORDER BY ...etc...

让我知道它是否有任何改进(但也可能会更慢)。另一个想法是使用一个包含您需要过滤的所有阶段的表:

CREATE TABLE filter_stage (
  stage varchar(255));

(255或尝试匹配sales_stage的实际长度,如果您也索引此列会更好)您输入所有要过滤的字符串:

INSERT INTO filter_stage VALUES ('Prospecting'), ('Appointment Set'), ('...'), ...

然后你从你的第一个查询中删除你的 IN 子句,然后你的 FROM 变成:

FROM
  opportunities INNER JOIN filter_stage
  ON opportunities.sales_stage = filter_stage.stage
  LEFT JOIN ...

让我知道它是否有效!

于 2012-11-19T17:40:01.703 回答
0

不要使用 IN。IN 在 mysql 中运行缓慢,使用 Exists

DROP TABLE IF EXISTS tempTable;
CREATE TEMPORARY TABLE tempTable ( sales_stage VARCHAR(50) NOT NULL );
insert into tempTable () values ('Prospecting'),('Appointment Set'),('MeetAndGreet'),...,('Service Pending');

SELECT
...
WHERE EXISTS(select sales_stage from tempTable where opportunities.sales_stage = sales_stage);
于 2012-11-19T17:08:28.190 回答