我都有哪些选择可以让我的 ORDER BY 更快?
Posted
技术标签:
【中文标题】我都有哪些选择可以让我的 ORDER BY 更快?【英文标题】:What options do I have to make my ORDER BY faster?我有哪些选择可以让我的 ORDER BY 更快? 【发布时间】:2009-01-21 21:07:20 【问题描述】:我有以下疑问:
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
【问题讨论】:
告诉我们您的 MySQL 版本以及您的索引是如何定义的... 索引在那里:KEYclient_name
(client_name
)
感谢添加..您有机会查看执行计划(解释 查看您的编辑
在这种情况下尝试使用 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
【讨论】:
你是对的,但这仍然不能解释为什么 order by 让事情变得如此缓慢...... 因为表格顺序是按照您的 PK 顺序排列的,所以如果您按 client_name 排序,它会执行书签查找来执行排序顺序,计划是什么样的?【参考方案2】:尝试将此密钥添加到client_projects
:
KEY(client_name, id, active_flag)
【讨论】:
【参考方案3】:可能在clients.id 和clients.active_flag 上有索引,因此优化器不需要转到完整表(或附加索引),除非您想对其进行排序。
检查优化器计划,我认为在 mySQL 中是解释。
client_name 上的索引,id 可能有帮助(或者它可能没有 - 检查计划)。
另外几个问题/想法/评论可能会有所帮助...
如果您从选择中得到的只是 id,为什么要按名称排序 如果您有“cp.project_id”的 where 子句,为什么还要左连接,这样无论如何都不会返回没有项目的客户对于其他海报(paul, eppz),对于拥有多个项目的客户可能需要“不同”。所以另一个想法是做类似
选择 ID 来自客户 c 存在于哪里 (select * from client_project cp where c.id = cp.client_id)
【讨论】:
我不确定在这种情况下是否属实,但如果 cp.project_id 是唯一字段,则不需要 distinct ,因为它在 where 明确指出 cp.project_id = 1子句。 好吧,你是对的......这是一个明智的假设,即 project_id 将是唯一的,然后不需要区分。【参考方案4】:我没有给你解决方案,但我有一个解释。
MySQL 每个表只使用一个索引。您有两个表,其中使用的索引是其中一个的主键(WHERE cp.project_id = 1),并且连接强制使用第二个表索引来有效连接。
在此之后使用 ORDER BY,因此 MySQL 无法使用索引进行排序。添加更多索引将无济于事。 EXPLAIN 将显示 MySQL 为每个表选择了哪些索引。强制索引会导致查询的其他部分变慢。
【讨论】:
【参考方案5】:c.id 是主键吗?如果是这样,您不应该对它执行 DISTINCT,因为它已经是不同的,并且强制 DISTINCT 可能会导致它按 id 排序,然后按 client_name 排序。
【讨论】:
【参考方案6】:一些优化是数据库供应商中立的,而其他优化是数据库供应商特定的。这里有几件事可以尝试。
按照其他地方的建议删除 DISTINCT。 考虑使用内连接。我知道在您的情况下这可能不是一个可行的选择。此外,运行执行计划以更好地了解正在发生的事情,即查询的哪些部分占用了最多的时间以及原因。有关详细信息,请参阅 EXPLAIN 关键字。
【讨论】:
通过在 WHERE 子句之前使用这个 WHERE cp.project_id = 1 而不是 AND cp.project_id = 1 无论如何它都是一个 INNEr JOIN @SQLMenace:如果您的查询优化器/规划器是智能的,那就是真的。我知道在很多这样的情况下,MSSQL 会进行笛卡尔连接,然后过滤结果。恕我直言,您应该始终在连接条件中限制连接以防万一。【参考方案7】:您需要在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
【讨论】:
【参考方案8】:c.id 是身份列吗?如果是,我认为您不需要 DISTINCT,因为每个 c.id 都是唯一的。
编辑
那么即使cp.project_id = 1,c.id也可能在cp中有多个条目?
编辑
只是好奇为什么在不选择客户名称时要按客户名称订购。
【讨论】:
-1:如果没有 JOIN,这将是正确的,但很有可能每个客户端有多个 client_project【参考方案9】:如果您甚至不退货,为什么要按客户名称订购?
你还需要独特的吗?
如果你的 where 子句无论如何都会使其成为内连接,你为什么要进行左连接
通过在 WHERE 子句之前使用 WHERE cp.project_id = 1 而不是 AND cp.project_id = 1,无论如何它都是一个 INNEr JOIN
【讨论】:
以上是关于我都有哪些选择可以让我的 ORDER BY 更快?的主要内容,如果未能解决你的问题,请参考以下文章