我有什么选择让我的ORDER BY更快?

时间:2009-01-21 21:07:21

标签: mysql query-optimization sql-order-by

我有以下查询:

SELECT DISTINCT c.id
FROM clients AS c
LEFT JOIN client_project AS cp ON (cp.client_id = c.id)
WHERE cp.project_id = 1
    AND c.active_flag = 1
ORDER BY c.client_name

如果我删除订单,查询需要0.005秒。使用order by,查询需要1.8-1.9秒。我有client_name的索引。

还有什么可以提高速度?

编辑: c.id是主键,但在client_project中可能有多条记录,因此每个ID可能会产生多条记录。此外,删除distinct会使查询产生0.1秒的差异。

添加:这是我的客户表:

CREATE TABLE IF NOT EXISTS `clients` (
  `id` int(11) NOT NULL auto_increment,
...
  `organization` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `client_name` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `active_flag` tinyint(1) NOT NULL,
...
  PRIMARY KEY  (`id`),
  KEY `active_flag` (`active_flag`),
...
  KEY `organization` (`organization`),
  KEY `client_name` (`client_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

使用MySQL 5.0

9 个答案:

答案 0 :(得分:2)

查看您的修改

在这种情况下尝试使用EXISTS

SELECT  c.id
FROM clients AS c
WHERE EXISTS (SELECT * FROM  client_project AS cp  
              WHERE cp.client_id = c.id and cp.project_id = 1)
AND c.active_flag = 1

答案 1 :(得分:2)

尝试将此密钥添加到client_projects

KEY(client_name, id, active_flag)

答案 2 :(得分:1)

可能在clients.id和clients.active_flag上有索引,因此除非你想对它进行排序,否则优化器不需要转到完整表(或附加索引)。

检查优化器计划,我认为在mySQL中是解释。

client_name上的索引,id可能有帮助(或者可能没有 - 检查计划)。

一些可能有帮助的附加问题/想法/评论......

  • 如果从select中获得的是id
  • ,为什么按名称排序
  • 如果你有一个“cp.project_id”的where子句,为什么左连接,所以没有项目的客户端不会被返回
  • 对于其他海报(paul,eppz),具有多个项目的客户可能需要“明显”。所以另一个想法是做像

    这样的事情

    选择ID 来自客户c 存在的地方 (从client_project cp中选择*,其中c.id = cp.client_id)

答案 3 :(得分:1)

我没有适合您的解决方案,但我确实有解释。

MySQL每个表只使用一个索引。您有两个表,其中使用的索引是一个主键(WHERE cp.project_id = 1),并且连接强制使用第二个表索引来有效地连接。

之后使用ORDER BY,因此MySQL无法使用索引进行排序。添加更多索引无济于事。 EXPLAIN将显示MySQL选择用于每个表的索引。强制索引将导致查询的其他部分变慢。

答案 4 :(得分:0)

c.id是主键吗?如果是这样,你不应该对它进行DISTINCT,因为它已经是不同的,强制DISTINCT可能会导致它按id排序,然后按client_name排序。

答案 5 :(得分:0)

某些优化是数据库供应商中立,而其他优化是数据库供应商特定。这里有几件事要尝试。

  • 按照别处的建议删除DISTINCT。
  • 考虑使用内部联接。我意识到在你的情况下这可能不是一个可行的选择。

此外,运行执行计划以更好地了解查询的哪些部分占用最多时间和原因。有关详细信息,请参阅EXPLAIN关键字。

答案 6 :(得分:0)

您需要强制使用client_name上的索引:

SELECT id
FROM (
  SELECT c.id,
    (
    SELECT 1
    FROM client_projects cp
    WHERE cp.client_id = c.id
      AND cp.project_id = 1
    LIMIT 1
    ) e
FROM clients c
FORCE INDEX (client_name)
WHERE c.active_flag = 1
ORDER BY
  client_name
) co
WHERE e IS NOT NULL

答案 7 :(得分:-1)

c.id是一个标识栏吗?如果是的话,我认为你不需要DISTINCT,因为每个c.id都是唯一的。

<强> 修改

所以即使cp.project_id = 1,c.id也可能在cp中有多个条目?

<强> 修改

当你没有选择它时,只想了解你为什么要按客户名称订购。

答案 8 :(得分:-2)

如果您还没有退回,为什么要按客户名称订购?

你还需要与众不同吗?

如果你的where子句会使它成为内连接

,你为什么要进行左连接?

通过在WHERE子句之前使用此WHERE cp.project_id = 1而不是AND cp.project_id = 1,无论如何它都是INNEr JOIN