【问题标题】:MySQL: Key/value store queries optimizationMySQL:键/值存储查询优化
【发布时间】:2015-05-07 02:04:36
【问题描述】:

我正在寻求帮助设置正确的索引(我尝试了太多,现在我有点迷路了),正确的 MySQL 引擎(MyIsam,InnoDB ...)并帮助解决我的查询(JOIN,...)。当我认为这些查询应该返回 count(*) 时,我也很头疼。

我每次查询的时间超过 5 到 10 秒,但我不确定是否可以为这个大型数据库获得更好的时间。

我正在尝试优化这个 MySQL 表:

项目(约 60 万行):

+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| type  | varchar(255)     | NO   | PRI | NULL    |                |
+-------+------------------+------+-----+---------+----------------+

Items_Relationships(~1M 行):

+-------------+------------------+------+-----+---------+-------+
| Field       | Type             | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| lft_item_id | int(11) unsigned | NO   | PRI | NULL    |       |
| rgt_item_id | int(11) unsigned | NO   | PRI | NULL    |       |
| rel_type    | varchar(255)     | NO   | PRI | NULL    |       |
+-------------+------------------+------+-----+---------+-------+

Items_Values(~4M 行):

+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| item_id | int(11) unsigned | NO   | PRI | 0       |                |
| name    | varchar(255)     | YES  | MUL | NULL    |                |
| value   | longtext         | YES  |     | NULL    |                |
| lang    | varchar(2)       | YES  |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

我基本上是在运行这些常见的查询:

1.查询 - 值“状态”> 1 的所有项目:

SELECT `company`.`id` AS `id`,
       `company`.`type` AS `type`
FROM `items` AS `company`
INNER JOIN `items_values` AS `value_name` ON (`company`.`id` = `value_name`.`item_id`)
WHERE `company`.`type` = 'company'
  AND `value_name`.`name` = 'status'
  AND CONVERT(`value_name`.`value`, SIGNED) > 1 
GROUP BY `company`.`id`
ORDER BY `company`.`id` DESC 
LIMIT 0, 30

2。查询 - 具有与其他项目相关的某些值的所有项目:

SELECT `company`.`id` AS `id`,
       `company`.`type` AS `type`
FROM `items` AS `company`
INNER JOIN `items_values` AS `value_status` ON (`value_status`.`item_id` = `company`.`id`)
INNER JOIN `items_relationships` AS `companies_categories` ON (`companies_categories`.`lft_item_id` = `company`.`id`)
INNER JOIN `items_values` AS `category_rgt` ON (`category_rgt`.`item_id` = `companies_categories`.`rgt_item_id`)
WHERE `company`.`type` = 'company'
  AND `company`.`type` = 'company'
  AND `value_status`.`name` = 'status'
  AND CONVERT(`value_status`.`value`, SIGNED) >= 1
  AND `category_rgt`.`name` = 'rgt'
  AND (CONVERT(category_rgt.value, UNSIGNED) BETWEEN 2805 AND 4222)
  AND `companies_categories`.`rel_type` = 'company_category'
GROUP BY `company`.`id`
ORDER BY `company`.`id` DESC LIMIT 10
OFFSET 0

提前谢谢!

【问题讨论】:

  • 键值存储的代码非常笨拙,而且无法扩展。这是一个关于如何做的博客。 mysql.rjweb.org/doc.php/eav
  • 看起来真的很有用,但我必须阅读更多次才能清楚。如果我们有这个带有示例的解决方案将帮助我更好地理解..

标签: php mysql optimization store key-value


【解决方案1】:

如果您询问索引,那么您需要的几乎所有内容都已编入索引。

我有一个问题

| name | varchar(255) | YES | MUL | NULL | |

所以我更喜欢设置它以及主键。

我对表结构只有一个建议。

如果您的

中混合了字符串和数字

| value | longtext | YES | | NULL | |

创建另一列int_value SIGNED 或无符号更好。

您也应该将该列设置为索引(只要您需要将该列用作过滤器和/或搜索条件)

并在适用的插入/更新时填写该字段。

此修改将提高查询的性能,您不应像此处那样对数百万条记录使用 CAST 和/或 CONVERT:

  AND CONVERT(`value_status`.`value`, SIGNED) >= 1
  AND (CONVERT(category_rgt.value, UNSIGNED) BETWEEN 2805 AND 4222)

所以我没有更多关于结构的知识了。

但我会请你试试我的查询,就像一个实验,如果它比你的更快。不幸的是,我无法使用任何数据进行调试。如果你提供一些 sqlfiddle 会有很大帮助。

SELECT `company`.`id` AS `id`,
       `company`.`type` AS `type`
FROM `items` AS `company`
INNER JOIN (
  SELECT
    item_id,
  FROM items_values
  WHERE name = 'status' 
       AND CONVERT(value, SIGNED) >= 1
) AS value_status
ON value_status.item_id = company.id

INNER JOIN 
(
  SELECT
    lft_item_id
  FROM
    items_relationships 
  INNER JOIN (
    SELECT
      item_id
    FROM 
      items_values
    WHERE name = 'rgt'
      AND (CONVERT(value, UNSIGNED) BETWEEN 2805 AND 4222)
   ) AS category_rgt
  ON category_rgt.item_id = items_relationships.rgt_item_id
  WHERE items_relationships.rel_type = 'company_category'

) as companies_categories
ON (`companies_categories`.`lft_item_id` = `company`.`id`)

WHERE `company`.`type` = 'company'
GROUP BY `company`.`id`
ORDER BY `company`.`id` DESC 

LIMIT 10

【讨论】:

  • 我稍微改进了 items_values 的设计,方法是创建额外的列 value_index 类型的 int 以防止 CONVERT 并在 name and value_index 上创建新的组合索引。我会试试结果
猜你喜欢
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 2011-07-07
  • 2018-12-21
相关资源
最近更新 更多