数百万行表的连接性能

时间:2016-01-25 18:00:59

标签: mysql database performance join database-design

我需要让我的网站用户能够选择他们的国家,省和城市。所以我想显示一个国家/地区列表,然后是所选国家/地区的省份列表,然后是所选省份的城市列表(我现在不想要任何其他UI解决方案)。当然,每个名称都必须使用用户的语言,因此我需要额外的表格进行翻译。

让我们关注城市的情况。以下是两个表格:

CREATE TABLE `city` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `province_id` int(10) unsigned DEFAULT NULL
  PRIMARY KEY (`id`),
  KEY `idx_fk_city_province` (`province_id`),
  CONSTRAINT `fk_city_province` FOREIGN KEY (`province_id`) REFERENCES `province` (`id`)
) ENGINE=InnoDB;

CREATE TABLE `city_translation` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `city_id` int(10) unsigned NOT NULL,
  `locale_id` int(10) unsigned DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL
  PRIMARY KEY (`id`),
  KEY `idx_fk_city_translation_city` (`city_id`),
  KEY `idx_fk_city_translation_locale` (`locale_id`),
  KEY `idx_city_translation_city_locale` (`city_id`,`locale_id`),
  CONSTRAINT `fk_city_translation_city` FOREIGN KEY (`city_id`) REFERENCES `city` (`id`),
  CONSTRAINT `fk_city_translation_locale` FOREIGN KEY (`locale_id`) REFERENCES `locale` (`id`)
) ENGINE=InnoDB;

city表包含4百万行,city_translation表包含4百万x我网站上可用语言的数量。现在这是1200万。如果将来我想支持10种语言,那将是4千万......

所以我想知道:处理这个大小的表是一个坏主意(表现明智),还是一个很好的索引(在连接字段city_idlocale_id)足以使尺寸无关紧要?

如果没有,用于解决这个问题的常用解决方案有哪些 - 但我觉得常见问题?我只对表现感兴趣。我可以在必要时进行非规范化,如果它们更合适,甚至可以使用其他工具(ElasticSearch?)。

1 个答案:

答案 0 :(得分:2)

摆脱city_translations中的id。取而代之的是PRIMARY KEY(city_id, locale_id)。使用InnoDB,由于在JOINs中删除了不必要的步骤,因此速度可能会加倍。您还可以通过删除以city_id开头的两个索引来缩小磁盘占用空间。

你认为你会超越16M城市吗?我对此表示怀疑。因此,通过将city_id更改为MEDIUMINT UNSIGNED来保存一个字节。

通过将locale_id更改为TINYINT UNSIGNED来保存3个字节。

这些节省量乘以提及它们的列数和索引数。

表格(GB)有多大? innodb_buffer_pool_size的设置是什么?有多少内存?看看你是否可以使该设置大于总表大小,但不超过可用内存的70%。 (这是唯一的"可调和#34;值得检查。)

我希望您为中国用户设置默认值CHARACTER SET utf8mb4。 (但这是另一个故事。)