MySql查询和表优化

MySql查询和表优化,mysql,Mysql,我试图在一个有500K条记录的表上运行下面的简单查询 SELECT COUNT(*) AS impressionCount FROM impression WHERE 0 = 0 AND impressionObjectId1 = 'C69A54B8-B828-E2E4-2319A93011DF4120' AND impressionObjectId2 = '1'; 运行此查询需要1

我试图在一个有500K条记录的表上运行下面的简单查询

SELECT COUNT(*) AS impressionCount
            FROM impression
            WHERE 0 = 0
                AND impressionObjectId1 = 'C69A54B8-B828-E2E4-2319A93011DF4120'
                AND impressionObjectId2 = '1';
运行此查询需要10秒。我尝试过为ImpressionObject1和ImpressionObject2列创建单独的索引,以及使用这两个列创建复合索引。这种组合在一段时间内运行良好,但现在也很缓慢

以下是我的表格结构:

DROP TABLE IF EXISTS `impression`;
CREATE TABLE `impression` (
  `impressionId` varchar(50) NOT NULL,
  `impressionObjectId1` varchar(50) NOT NULL,
  `impressionObjectId2` varchar(50) default NULL,
  `impressionStampDate` datetime NOT NULL,
  PRIMARY KEY  (`impressionId`),
  KEY `IX_object` (`impressionObjectId1`,`impressionObjectId2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC COMMENT='InnoDB free: 191488 kB';
如有任何建议,将不胜感激。谢谢

编辑:添加解释时,这是输出:

1, 'SIMPLE', 'impression', 'ref', 'IX_object', 'IX_object', '105', 'const,const', 304499, 'Using where; Using index'
如果反复运行该精确查询,则可以缓存结果。每次使用impressionObjectId1='C69A54B8-B828-E2E4-2319A93011DF4120'和impressionObjectId2='1'插入到表中时,递增一个计数器,每次删除时递减计数器

如果您的查询有相对较少的uniqe案例,那么这将是一个很好的性能提升器,尽管它对数据完整性没有那么好,必须小心使用。

如果您反复运行这个精确的查询,那么您可以缓存结果。每次使用impressionObjectId1='C69A54B8-B828-E2E4-2319A93011DF4120'和impressionObjectId2='1'插入到表中时,递增一个计数器,每次删除时递减计数器


如果查询的uniqe案例数量相对较少,那么这将是一个很好的性能提升器,尽管它对数据完整性没有那么好,必须小心使用。

在为VARCHAR字段创建索引时,使用col\u nameX语法仅在前X个字符上创建索引通常很有帮助


如果字段的前X个字符足以区分行,则通过这种方式索引效率更高,这取决于您所在的数据类型。如果列包含示例第1列中的GUID或第2列中的非常短的文本,则仅为前10个左右的字符创建索引可以真正提高性能

为VARCHAR字段创建索引时,使用col_nameX语法,仅在前X个字符上创建索引通常很有帮助


如果字段的前X个字符足以区分行,则通过这种方式索引效率更高,这取决于您所在的数据类型。如果列包含示例第1列中的GUID或第2列中的非常短的文本,则仅为前10个左右的字符创建索引可以真正提高性能

我注意到在您的解释中,您的“行”值非常高。结果集中应该有多少行?请注意,解释中的行数是为了查找结果集而必须搜索的行数,而不是结果集中的行数

您可以颠倒索引的顺序并获得一些效率

通常,您希望将最有选择性的列放在索引的第一位,以便可能匹配的行数最小

这里有一个很好的技巧可以找到最有选择性的列:

SELECT SUM(impressionObjectId1 = 'C69A54B8-B828-E2E4-2319A93011DF4120'),
       SUM(impressionObjectId2 = '1')
            FROM impression;
选择最多的列的和值最低。将该列放在索引的第一位


你也可以只创建两个索引,一个是另一个的反向,让MySQL选择最好的。

我注意到在你的解释中,你的“行”值非常高。结果集中应该有多少行?请注意,解释中的行数是为了查找结果集而必须搜索的行数,而不是结果集中的行数

您可以颠倒索引的顺序并获得一些效率

通常,您希望将最有选择性的列放在索引的第一位,以便可能匹配的行数最小

这里有一个很好的技巧可以找到最有选择性的列:

SELECT SUM(impressionObjectId1 = 'C69A54B8-B828-E2E4-2319A93011DF4120'),
       SUM(impressionObjectId2 = '1')
            FROM impression;
选择最多的列的和值最低。将该列放在索引的第一位


您也可以创建两个索引,一个索引与另一个索引相反,并让MySQL选择最佳索引。

Show EXPLAIN for the query。还有,为什么是varchar50而不是char32?@zerkms:Explain-output-added。看到什么不寻常的地方了吗?是30万行满足了这个条件?@zerkms:是的,是30万行。这是一个对象显示横幅的次数计数。大约有30%的匹配范围,之后mysql决定使用fullscan而不是索引查找,因为它速度更快。你有300/500==60%。因此,至少我不知道有什么方法可以加速您的查询。请为查询显示解释。还有,为什么是varchar50而不是char32?@zerkms:Explain-output-added。看到什么不寻常的地方了吗?是30万行满足了这个条件?@zerkms:是的,是30万行。这是一个对象显示横幅的次数计数。大约有30%的匹配范围,之后mysql决定使用fullscan而不是索引查找,因为它速度更快。你有300/500==60%。所以至少我没有办法
我不知道如何加快你的查询。嗨,君王。谢谢,但这是一个简单的查询,我宁愿找出它为什么慢,也不愿使用缓存来掩盖问题。@厚脸皮:尽管它很简单,但它返回的数据太多。它返回的是计数,因此数据是最小的,不是吗。谢谢,但这是一个简单的查询,我宁愿找出它为什么慢,也不愿使用缓存来掩盖问题。@厚脸皮:尽管它很简单,但它返回的数据太多。它返回的是计数,因此数据很小,否??在这种情况下,绝对没有理由反转索引。但我不明白的是,即使是没有任何WHERE语句的简单计数也需要同样长的时间。当然计数应该快吗?@checkey:COUNT*只有在myisam才快。@zerkms:那你有什么建议?因为InnoDB更适合插入和更新,而myIsam更适合读取。然而,我们有一张桌子经常同时做这两件事。我将尝试更改表格类型,看看结果如何。谢谢。在这种情况下,绝对没有理由反转索引。但我不明白的是,即使是没有任何WHERE语句的简单计数也需要同样长的时间。当然计数应该快吗?@checkey:COUNT*只有在myisam才快。@zerkms:那你有什么建议?因为InnoDB更适合插入和更新,而myIsam更适合读取。然而,我们有一张桌子经常同时做这两件事。我将尝试更改表格类型,看看结果如何。谢谢