3

首先,这个问题是关于 MySQL 3.23.58 的,所以请注意。

我有 2 个具有以下定义的表:

Table A: id INT (primary), customer_id INT, offlineid INT

Table B: id INT (primary), name VARCHAR(255)

现在,表 A 包含 65k+ 条记录,而表 B 包含约 40 条记录。除了2个主键索引外,A表的offlineid字段上也有一个索引。每个表的字段比较多,但是对于这个查询来说,它们是不相关的(我看到了,如果需要的话问一下)。

我首先看到了以下查询(查询时间:~22 秒):

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

现在,medie 中的每个 id 都与不同的名称相关联,这意味着您可以按 id 和名称进行分组。一些来回的测试让我解决了这个问题(查询时间:~6 秒):

SELECT a.name, COUNT(*) AS orders, COUNT(DISTINCT(b.kundeid)) AS leads
FROM medie a
INNER JOIN katalogbestilling_katalog b ON a.id = b.offline
GROUP BY b.offline;

有什么办法可以将它调低到“即时”时间(最坏的情况下最多 1 秒)?我在offlineid上添加了索引,但除此之外和查询的重新安排,我不知道该怎么办。EXPLAIN 查询显示查询正在使用 fileshort(原始查询也使用临时表)。欢迎所有建议!

4

9 回答 9

1

我猜你的主要问题是你使用的是旧版本的 MySQL。也许 MySQL 3 不喜欢 COUNT(DISTINCT())。

或者,它可能只是系统性能。你有多少内存?

尽管如此,MySQL 3 真的很老了。我至少会组装一个测试系统,以查看更新版本是否更快地运行该查询。

于 2008-09-22T11:36:28.603 回答
1

不幸的是,mysql 3 不支持子查询。我怀疑通常是旧版本导致性能下降。

于 2008-09-22T12:10:34.557 回答
0

kundeid是如何定义的?查看两个表的完整模式(由 MySQL 生成,即带有索引)以及 EXPLAIN 的输出以及上面的查询会很有帮助。

调试此问题并找出瓶颈的最简单方法是开始从查询中逐个删除字段并测量运行需要多长时间(请记住在运行每个查询之前运行 RESET QUERY CACHE)。在某些时候,您会看到执行时间显着下降,然后您就确定了瓶颈。例如:

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

可能会变成

SELECT b.name, COUNT(DISTINCT(a.kundeid)) AS leads
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

消除“订单”成为瓶颈的可能性,或

SELECT b.name, COUNT(*) AS orders
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

从等式中消除“线索”。这将引导您朝着正确的方向前进。

更新:我不建议从最终查询中删除任何数据。只需删除它们以减少变量的数量,同时寻找瓶颈。鉴于你的评论,我明白了

SELECT b.name
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

还是表现不佳?这显然意味着它要么是未优化的联接,要么是分组依据(您可以通过删除分组依据进行测试 - 联接仍然很慢,在这种情况下,这是您需要解决的问题,或者它不会- 在这种情况下,显然是 GROUP BY)。你可以发布的输出

EXPLAIN SELECT b.name
FROM katalogbestilling_katalog a, medie b
WHERE a.offlineid = b.id
GROUP BY b.name

以及表模式(以便于调试)?

更新#2

还有一种可能是您的所有索引都已正确创建,但是当涉及到最大内存使用量或其他类似的东西迫使它使用磁盘排序时,您的 mysql 安装配置错误。

于 2008-09-22T11:37:15.510 回答
0

如果删除内部连接并用嵌套的 select 语句替换它,同时删除 count(*) 并将其替换为 PK,则性能可能会略有提高。

SELECT a.name, COUNT(*) AS orders, COUNT(DISTINCT(b.kundeid)) AS leads FROM medie aINNER JOIN katalogbestilling_katalog b ON a.id = b.offline GROUP BY b.offline;

将会

SELECT a.name, COUNT(a.id) AS orders, (SELECT COUNT(kundeid) FROM katalogbestilling_katalog b WHERE b.offline = a.id) AS Leads FROM medie a;

于 2008-09-22T11:57:24.557 回答
0

好吧,如果查询运行的频率足以保证开销,请在表 A 上创建一个索引,其中包含查询中使用的字段。然后可以从索引中读取所有结果,而不必扫描表。

也就是说,我所有的经验都是基于 MSSQL,所以可能行不通。

于 2008-09-22T12:12:49.327 回答
0

您的第二个查询很好,65k+40k 行不是很大:)

在 katalogbestilling_katalog.offline 列上放置一个新索引,它会为您运行得更快。

于 2008-09-22T13:17:05.600 回答
0

您可以尝试确保在每个表上定义了覆盖索引。覆盖索引只是一个索引,其中在选择中请求或在连接中使用的每一列都包含在索引中。这样,引擎只需读取索引条目,而不必执行相应的行查找来获取任何未包含在索引中的请求列。我在 Oracle 和 MS SqlServer 中成功使用了这种技术。

查看您的查询,您可以尝试:

medie.id、medie.name 的
一个索引katalogbestilling_katalog.offlineid、katalogbestilling_katalog.kundeid 的一个索引

应按这些顺序为索引定义列。是否可以使用索引会有所不同。

更多信息在这里:

涵盖索引信息

于 2008-09-22T14:59:36.040 回答
0

尝试向 (offlineid, kundeid) 添加索引

我在目录中添加了 180,000 个 BS 行,在 medie 中添加了 30,000 个 BS 行(katalog offlineid's 对应于 medie id's 和一些重叠的 kundeid's 以确保区分计数有效)。请注意,这是在 mysql 5 上,所以如果你没有类似的结果,mysql 3 可能是你的罪魁祸首,但据我回忆,mysql 3 应该能够很好地处理这个问题。

我的桌子:

CREATE TABLE `katalogbestilling_katalog` (
  `id` int(11) NOT NULL auto_increment,
  `offlineid` int(11) NOT NULL,
  `kundeid` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `offline_id` (`offlineid`,`kundeid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=60001 ;

CREATE TABLE `medie` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=30001 ;

我的查询:

SELECT b.name, COUNT(*) AS orders, COUNT(DISTINCT(a.kundeid)) AS leads
FROM medie b
INNER JOIN katalogbestilling_katalog a ON b.id = a.offlineid
GROUP BY a.offlineid
LIMIT 0 , 30


"Showing rows 0 - 29 (30,000 total, Query took 0.0018 sec)"

并解释:

id:  1
select_type:    SIMPLE
table: a
type: index
possible_keys:  NULL
key:    offline_id
key_len:    8
ref: NULL
rows: 180000
Extra: Using index

id: 1
select_type:    SIMPLE
table: b
type: eq_ref
possible_keys:  PRIMARY
key:    PRIMARY
key_len:    4
ref: test.a.offlineid
rows: 1
Extra:
于 2008-09-22T15:13:53.057 回答
0

尝试优化服务器本身。有关最重要的变量,请参阅Peter Zaitsev 的这篇文章。有些是 InnoDB 特定的,而另一些是针对 MyISAM 的。您没有提到您使用的引擎在这种情况下可能相关(例如,MyISAM 中的 count(*) 比 InnoDB 中的快得多)。 这是来自同一个博客的另一篇文章,以及来自MySQL Forge的一篇文章

于 2008-09-22T16:54:33.237 回答