3

我正在一个现在拥有数百万条记录的网站上工作(抱歉无法透露哪个网站)最初它只有几百条记录,所以下面的查询是可以接受的

查询:SELECT * FROM….WHERE category LIKE '%,3,%';

但是现在它只是杀死了数据库,因为对于每个查询,它必须通过上述查询遍历整个 2Mil 记录

分类表
ID NAME
1 女
2 时尚
3 服装
4 配饰
5 上衣
6 连衣裙
7 耳环
8 短裙
9 长裙
10 男

产品表
ID…..类别….其他位
1 ,1,2,3,6,9, ……<br> 2 ,1,2,4,7,
3 ,1,2,3,5,
4 , 10,2,3,4,

你有上面发生的事情的图片。现在,如果我对产品表中的类别行进行全文索引,它只会给出 1 个基数:(

我该如何克服呢?我考虑过为每个类别复制行,但数据库目前很大,有 2 GIG,如果有重复,它将变成大约 10 GIG……更像是一个问题,而不是一个解决方案

4

3 回答 3

2

请记住,将数字存储为字符串所需的每个数字的字节数大约是将数字存储为整数的两倍。加上所有这些逗号。

因此,如果您担心空间,那么以标准化方式存储数据不会像您担心的那样扩展。

它将允许您编写利用索引的适当查询。因此,如果有一些扩展,您将牺牲一点存储空间来大幅提高速度。

提示:如果您使用 InnoDB,主键不会占用任何存储空间,因为表本身存储为主键索引。如果您需要按类别优化搜索,您应该首先使用类别 ID 定义规范化表,然后再定义产品 ID。

CREATE TABLE CategoryProduct (
  categoryid INT,
  productid INT,
  PRIMARY KEY (categoryid, productid)
);

另请参阅我对在数据库列中存储分隔列表真的那么糟糕吗?了解使用逗号分隔列表的更多缺点。

于 2013-07-25T02:00:49.460 回答
1

我会考虑一个新表,比如说Product_Category(我知道这太不可思议了),其中每一行都包含一个与该类别的外键 (FK) 关系Product.id的列和一个类别的列。

category列可能TINYINT只需要 1 个字节来存储,而我猜 FK 列将与 Product.id 列相同(可能INT- 4 个字节),然后您可以索引这两个列,以便您可以找出哪个产品所属的类别以及哪些产品属于某个类别。此外,此表不需要Primary Key(ie id),为您节省了额外的 4 个字节。

(请参阅MySQL 数据类型存储要求

使用这个解决方案,这个新数据库中的每一行将占用大约 5 个字节。由于字符串中的每个字符占用 1 个字节(假设 ASCII 和 latin1 编码),因此通过删除Product.category项目并将其放入 中,您将看到每个产品每个类别增加 3 个字节(包括逗号) Product_Category,但这远不及复制整个产品行是一个很大的收获。然而,改变你的代码是有代价的(除非你比我好得多joins)。

这有帮助吗?

于 2013-07-25T01:26:28.907 回答
0

我见过的一种解决方案是使用三个表:

  • 类别列出您的类别
  • products列出您的产品,没有任何附加的类别信息
  • category_map是一个特殊的表:每一行将一个 product_id 链接到一个 category_id

要按类别查找产品,您可以将 category_map 中的行与产品中的行进行匹配。

这是一个不完美的例子,但它得到了它的要点:

SELECT * FROM 
(
    SELECT * FROM category_map 
    WHERE category_id=1
) AS map 
INNER JOIN products 
ON products.id = map.product_id;

表连接是一个非常强大的工具;如果您不熟悉使用它们,您可能需要花一些时间阅读它们。Coding Horror 有一个略过细节的视觉解释

最好设置外键约束或以其他方式确保category_map中的条目对应于productscategories中的现有条目。

于 2013-07-25T01:27:43.293 回答