1

我有以下查询:

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

4

9 回答 9

2

尝试将此密钥添加到client_projects

KEY(client_name, id, active_flag)
于 2009-01-22T01:13:29.047 回答
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
于 2009-01-21T21:21:16.740 回答
1

我没有给你的解决方案,但我有一个解释。

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

之后使用 ORDER BY,MySQL 就不可能使用索引进行排序。添加更多索引无济于事。EXPLAIN 将显示 MySQL 为每个表选择了哪些索引。强制索引会导致查询的其他部分变慢。

于 2009-02-18T22:33:01.347 回答
1

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

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

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

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

  • 如果您从选择中得到的只是 id,为什么要按名称排序
  • 如果您有“cp.project_id”的where子句,为什么要左连接,所以无论如何都不会返回没有项目的客户
  • 至于其他海报(paul, eppz),对于拥有多个项目的客户可能需要“不同”。所以另一个想法是做类似的事情

    从存在的客户端 c 中选择 id(从 client_project cp where c.id = cp.client_id 中选择 *)

于 2009-01-21T21:22:52.603 回答
0

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

于 2009-01-21T21:11:14.077 回答
0

一些优化是 DB 供应商中立的,而其他优化是 DB 供应商特定的。这里有几件事可以尝试。

  • 按照其他地方的建议删除 DISTINCT。
  • 考虑使用内连接。我意识到在您的情况下这可能不是一个可行的选择。

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

于 2009-01-21T21:16:23.443 回答
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
于 2009-02-18T15:15:50.463 回答
-1

c.id 是身份列吗?如果是,我认为您不需要 DISTINCT ,因为每个 c.id 都是唯一的。

编辑

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

编辑

只是好奇为什么在不选择客户名称时要按客户名称订购。

于 2009-01-21T21:10:42.017 回答
-2

如果您甚至不退货,为什么要按客户名称订购?

你还需要独特的吗?

如果您的 where 子句无论如何都会使其成为内部联接,那么您为什么要进行左联接

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

于 2009-01-21T21:14:23.400 回答