如何禁食 return 并根据另外两个 table 的过滤器从一个 table 中计算行数

How to fast return and count rows from one table based on filter by two another tables

我有 3 个 table:

产品(1 500 000 行)

+------------+-------------+-------------+-------------+
|     id     |     shop    |    brand    |   category  |
+------------+-------------+-------------+-------------+

id int(11), AI, PK;
shop int(11);
brand int(11);
category int(11);

标签(1 300 000 行)

+------------+------------+-------------+
|     id     |   product  |     tag     |
+------------+------------+-------------+

id int(11), AI, PK;
product int(11) - it's id from 'products' table;
tag int(11);

大小(1 300 000 行)

+------------+------------+-------------+
|     id     |   product  |     size    |
+------------+------------+-------------+

id int(11), AI, PK;
product int(11) - it's id from 'products' table;
tag int(11);

每列都有索引。

我需要过滤所有可能按品牌、商店、类别、标签、尺寸过滤的产品(包括计数行)。因此,例如,如果我只需要显示 brand=1 和 shop=1 的产品,我将不会使用 tagssizes tables。这很简单。但问题是,当我想显示某些类别的所有产品时,一些商店有一些品牌、一些标签和一些尺寸。

有很多组合可以全部缓存和更新。获取实时计数成本约为 6 秒。由于分页限制,显示所有筛选的产品很快。

我花了一个多星期来测试什么更快,哪个数据库的选项和结构更好,但绝对不知道让它比这更快:

select p.id
  FROM
products p
  INNER JOIN tags t ON(p.id = t.product and tags=2) 
  INNER JOIN sizes s ON(p.id = s.product and sizes in (1,2))
  WHERE
p.shop in (1,13,31,65)
  and 
p.category in (270,126,127,144,143,145,146,839,147,148,149,150,158,151,155,157,123,124,128,129,602,120,121,122,152,153,154,482,526,40,42,46,115,119,138,142,133,135,136,137,130,131,132,116,117,32,103,485,112,113,114,566,39,107,108,109,110,118,265,516,527,528,529,530,106,159,161,185,30,86,87,88,89,90,91,92,267,531,532,104,105,28,29,31,33,34,35,36,37,38,41,43,44,45,102,165,269,487,2)
  GROUP BY p.id

现在只有 1,5M 产品,基于类别的过滤有 200k 产品(因为树顶)加载(计算和显示数据)大约 5 秒。这是因为过滤后的产品在 200k 产品类别中有 13k 行的结果。但是仍然需要在所有数据table中进行比较和搜索。解决方案之一可能是将所有产品分隔到 f.e。 10 table 个类别(服装、电器、药店、食品...)并在那里进行搜索。但我认为这不是解决问题的最佳方法。只是比现在更好。

order by p.id DESC limit 0,120 执行此 SQL 的结果非常快。大约 0.8 秒,但在某些情况下计算它们大约是 8-12 秒。是否有机会通过更改 SQL 查询或更改数据库结构来加快结果和计数?

感谢您的帮助。

  1. 尝试为所有类型的过滤制作单独的缓存。例如:
$tagProductIds = $yourCachingSystem->getAllIdsByTag($_POST['tag']);
$sizeProductIds = $yourCachingSystem->getAllIdsBySize($_POST['size']); 
$categoryProductIds = $yourCachingSystem->getAllIdsByCategory($_POST['category']); 

//...other filters by the product table

$neededProductIds = array_intersect($tagProductIds, $sizeProductIds, $categoryProductIds
//...other filtered ids
);

return $yourOrm->fetchAll(" ... product.id IN ($neededProductIds)");
  1. 您可以使用 MEMORY 引擎创建 MySQL 个表。这些表存储在 RAM 中,也许这会加快数据的提取速度。
CREATE TABLE if not exists  `products_tmp`
(
   //cols and indexes
) ENGINE = MEMORY
SELECT * products; //tags, sizes