提问者:小点点

数百万行表上的联接性能


我需要给我的网站用户的能力,选择他们的国家,省和市。所以我想显示一个国家列表,然后是所选国家的省份列表,然后是所选省份的城市列表(我现在不需要任何其他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表包含400万行,city\u翻译表包含400万行×我的网站上可用的语言数。现在是1200万。如果将来我想支持10种语言,那将是4000万。。。

所以我想知道:使用这种大小的表是一个坏主意(性能方面),还是一个好的索引(在连接字段中,city\u idlocale\u id)足以使大小变得无关紧要?

如果不是的话,解决这个特定的——但我想是常见的——问题的常见解决方案是什么?我只对表演感兴趣。如果必要的话,我可以去规范化,如果更合适的话,甚至可以使用其他工具(ElasticSearch?)。


共1个答案

匿名用户

摆脱城市翻译中的id。而是使用主键(城市id、地区id)。使用InnoDB,由于在连接中删除了不必要的步骤,这可能会使速度加倍。您还可以通过删除以city\u id开头的两个索引来缩小磁盘占用空间。

你认为你会超越1600万个城市吗?我对此表示怀疑。因此,通过将(所有表中的)city\u id更改为MEDIUMINT UNSIGNED来保存一个字节。

通过将locale\u id更改为TINYINT UNSIGNED保存3个字节。

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

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

为了中国用户的利益,我希望您有一个默认的字符集utf8mb4。(但这是另一回事。)