Mysql 在联接时查询大型数据集(1500多万行)

Mysql 在联接时查询大型数据集(1500多万行),mysql,mariadb,Mysql,Mariadb,我试图加入两个表,产品和产品市场。虽然产品的记录低于100万条,但产品市场的记录接近2000万条。数据已更改,因此架构创建表中可能有一两个输入错误: CREATE TABLE `products_markets` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `product_id` int(10) unsigned NOT NULL, `country_code_id` int(10) unsigned NOT NULL, `

我试图加入两个表,产品和产品市场。虽然产品的记录低于100万条,但产品市场的记录接近2000万条。数据已更改,因此架构创建表中可能有一两个输入错误:

CREATE TABLE `products_markets` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(10) unsigned NOT NULL,
  `country_code_id` int(10) unsigned NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_index` (`product_id`,`country_code_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21052102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `manufacturer_id` int(10) unsigned NOT NULL,
  `department_id` int(10) unsigned NOT NULL,
  `code` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `popularity` int(11) DEFAULT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `value` bigint(20) unsigned NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `products_code_unique` (`code`),
  KEY `products_department_id_foreign` (`department_id`),
  KEY `products_manufacturer_id_foreign` (`manufacturer_id`),
  CONSTRAINT `products_department_id_foreign`
       FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`),
  CONSTRAINT `products_manufacturer_id_foreign`
       FOREIGN KEY (`manufacturer_id`) REFERENCES `manufacturers` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=731563 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
我试图返回特定国家最受欢迎产品的50条记录,我的时间大约在50秒左右,似乎比预期的要高

我尝试了几个不同的查询,但没有成功:

select  `products_markets`.`product_id`
    from  products_markets
    left join  
        ( SELECT  products.id, products.popularity
            from  products
        ) p  ON p.id = products_markets.product_id
    where products_markets.country_code_id = 121
    order by  `popularity` desc, `p`.`id` asc
    limit  50 

此查询的解释是:

id  select_type  table              type possible_keys key           key_len refs             rows              extra
1   PRIMARY      products           ALL  PRIMARY       NULL          NULL    NULL             623848            Using temporary; Using filesort
1   PRIMARY      products_markets   ref  unique_index  unique_index  4       main.products.id 14                Using where; Using index; FirstMatch(products)
我喜欢的一个选择是将每个国家的产品和市场分成单独的表格,以减少查询。我曾尝试向服务器添加更多内存,但没有多大成功。有人能识别出数据库设计/查询中的任何明显错误吗


还有什么其他选项可以使此查询只占当前~50秒的一小部分?

试试这个我所说的查询,您首先从指定国家的“从产品市场”表中选择所有产品,而不是根据受欢迎程度从“产品表”中选择这些产品,并将其限制为50。尽量不要使用产品。*并仅选择需要数据的字段

select  products_markets.product_id, products_markets.county_code_id,
        products.*
    from  products_markets,products
    where  products_markets.country_code_id = 121
      and  products_markets.product_id=products.id
    group by  `products`.`name`, `products`.`manufacturer_id`
    order by  `products_markets.popularity` desc, `products`.`id` asc
    limit  50
在产品和市场中去掉id并添加

然后去掉唯一键,除非其他查询需要它

这将大大减少该大型表的磁盘占用空间,从而可能加快所有涉及该表的查询


这将有助于哈马扎建议的重新表述。

解释告诉你什么?你在使用索引吗?我想你应该在两个table@bhttoan我在上一个查询中添加了一个解释,这个查询大约需要40秒;然而,当我第二次运行它时,它似乎缓存了结果。虽然这可能会稍微快一点,但我确实需要将查询缩短很多。@chasenyc您应该在产品市场上设置国家/地区代码id索引时尝试此查询table@chasenyc另一种选择是,对市场上的产品应用限制过滤器,但在这种情况下,您不会得到最受欢迎的50products@HamzaDairywala-更具体地说,是INDEXcountry\u code\u id、product\u id。如果它不影响其他查询,只需颠倒唯一键中列的顺序。我添加了ALTER TABLE products\u markets ADD INDEX code\u id country\u code\u id,查询时间为~46秒删除时间戳可以显著减少查询时间,还是差异可以忽略不计?@chasnyc不,除非您在sql查询中选择该字段,否则影响不大,但是如果不需要时间戳,那么最好不要将不需要的数据存储到数据库中。这样做是有效的,删除主键并将其重置为复合键会使我的查询缩短到3秒。
select  products_markets.product_id, products_markets.county_code_id,
        products.*
    from  products_markets,products
    where  products_markets.country_code_id = 121
      and  products_markets.product_id=products.id
    group by  `products`.`name`, `products`.`manufacturer_id`
    order by  `products_markets.popularity` desc, `products`.`id` asc
    limit  50
PRIMARY KEY(country_code_id, product_id)