在 MySQL 中搜索属性的最佳方法

发布于 2025-01-15 11:40:04 字数 341 浏览 2 评论 0原文

您好,有一个用户表,我们在其中存储一些顶级字段,例如 userid、createdOn、email

以及第二个名为“属性”的表,用于存储附加属性的键值对。像 userid、key、value

键可能是姓名、电话、性别等。

不可能将其展平,因为我们可能添加新属性并且不想更改表。

我们的 users 表中有超过 1000 万行,properties 表中有超过 1 亿行。

查询这样的系统的最佳方法是什么?我们目前对表进行联接并使用基本的 where 子句。

有没有更高级的方法来处理这样的数据?我们经常需要搜索多个字段,例如名称“%jo”、性别=男性、国家=usa 和 foo=bar

Hi have a table of users where we store some top level fields like userid, createdOn, email

And a second table called properties that stores a key value pair of additional properties. Like userid, key, value

Keys may be things like name, phone , gender etc.

It’s not possible to flatten this because we may add new properties and don’t want to alter the table.

We have over 10 milllion rows in the users table and over 100 million in the properties table.

What’s the best way to query a system like this. We currently do a join on the tables and a basic where clause.

Are there any more advanced ways of working with data like this? We often have to search on multiple fields, like name like ‘%jo’ and gender=male and country =usa and foo=bar

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

踏月而来 2025-01-22 11:40:04

您所描述的通常称为实体属性值或 EAV。对于您所描述的情况来说,这是很常见的,您拥有比普通列更多的潜在属性。

CREATE TABLE eav_table (
  entity INT NOT NULL,
  property VARCHAR(64) NOT NULL,
  value VARCHAR(64),
  PRIMARY KEY (entity, property),
  KEY (entity, property, value)
);

前两列是表的主键,因为每个这样的对只有一行。但为所有三列设置二级索引很有用,因为这将是查询最常读取的索引。

使用相等条件查询多个值是可以的。 MySQL 可以进行元组比较。

SELECT ...
FROM eav_table
WHERE entity = 1234 AND (property, value) IN (
 ('gender', 'male'),
 ('country', 'usa'),
 ('foo', 'bar')
)

如果(entity, property, value)上有索引,优化器将使用它,并有效地找到匹配的行。

缺点是此语法不支持 LIKE 或任何其他类型的模式。因此,您需要更明确地执行这些操作:

SELECT ...
FROM eav_table
WHERE entity = 1234 AND property = 'name' AND value LIKE '%jo'

索引仍然会提供部分帮助,因为 entityproperty 是索引的最左边的列。但是带有前导通配符的 LIKE 模式无论如何都不能使用索引,因此它必须检查与前两列匹配的所有行,并测试每一行的模式。效率稍低,但至少可以缩小搜索范围。

如果您还想进行“哪些实体拥有美国国家财产?”之类的搜索您可能需要另一个具有不同列的二级索引作为最左边的列:

ALTER TABLE eav_table ADD KEY (property, value);

然后您可以搜索属性/值并获取一组匹配的实体:

SELECT ...
FROM eav_table
WHERE (property, value) = ('country', 'usa')

如果您有正确的索引来支持您需要执行的搜索,甚至具有数百万或数亿行的表效果很好。但最终随着表变得越来越大,您可能必须将其拆分为多个表或多个 MySQL 实例。提前规划无限增长的数据库需要您进行一些容量规划和基准测试。

What you're describing is usually called Entity-Attribute-Value, or EAV. It's a pretty common for the situation you describe, where you have more potential properties than you could make normal columns for.

CREATE TABLE eav_table (
  entity INT NOT NULL,
  property VARCHAR(64) NOT NULL,
  value VARCHAR(64),
  PRIMARY KEY (entity, property),
  KEY (entity, property, value)
);

The first two columns are the primary key of the table because you have only one row for each such pair. But it's useful to have a secondary index for all three columns, because that will be the one the query reads most often.

Querying multiple values with equality conditions is okay. MySQL can do tuple comparisons.

SELECT ...
FROM eav_table
WHERE entity = 1234 AND (property, value) IN (
 ('gender', 'male'),
 ('country', 'usa'),
 ('foo', 'bar')
)

If there's an index on (entity, property, value), the optimizer will use it, and find the matching rows efficiently.

The downside is that this syntax does not support LIKE or any other kind of patterns. So you would need to do those more explicitly:

SELECT ...
FROM eav_table
WHERE entity = 1234 AND property = 'name' AND value LIKE '%jo'

The index will still help partially, because entity, property are the left-most columns of the index. But a LIKE pattern with a leading wildcard cannot use an index regardless, so it will have to examine all rows that match the first two columns, and test each one for the pattern. A little less efficient, but at least it will narrow down the search.

If you also want to do searches like "which entities have the country property usa?" you would want another secondary index with different columns as the left-most columns:

ALTER TABLE eav_table ADD KEY (property, value);

Then you could search for the property/value and get a set of entities that match:

SELECT ...
FROM eav_table
WHERE (property, value) = ('country', 'usa')

If you have the right indexes to support the searches you need to do, even a table with millions or hundreds of millions of rows works pretty well. But eventually as the table gets larger and larger, you may have to split it into multiple tables or multiple MySQL instances. Planning ahead for databases that grow indefinitely requires you to do some capacity planning and benchmarking.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文