Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL性能:在公共外键上连接两个表:still;使用where";_Mysql_Database_Query Optimization_Database Performance_Database Optimization - Fatal编程技术网

MySQL性能:在公共外键上连接两个表:still;使用where";

MySQL性能:在公共外键上连接两个表:still;使用where";,mysql,database,query-optimization,database-performance,database-optimization,Mysql,Database,Query Optimization,Database Performance,Database Optimization,我有以下表格:测试用户,测试标签,产品,产品信息(产品信息有一个外键指向产品) 此外,我还有一些表,它们模拟了前面的表之间的一些关系:test\u-usertaging(FK到test\u-tag和test\u-user)、productinfo-tags(FK到test\u-tag和test\u-productinfo) (下面我附上一个更完整的描述,但这是主要的想法) 现在我有了一个产品ID和用户ID的列表,我想找到它们之间的共同标签,以及来自test\u usertagging的附加ext

我有以下表格:
测试用户
测试标签
产品
产品信息
产品信息
有一个外键指向
产品

此外,我还有一些表,它们模拟了前面的表之间的一些关系:
test\u-usertaging
(FK到
test\u-tag
test\u-user
)、
productinfo-tags
(FK到
test\u-tag
test\u-productinfo

(下面我附上一个更完整的描述,但这是主要的想法)

现在我有了一个产品ID和用户ID的列表,我想找到它们之间的共同标签,以及来自
test\u usertagging
的附加
extra\u info
列:

mysql> explain SELECT `test_usertagging`.`user_id`, `test_usertagging`.`tag_id`, `test_usertagging`.`extra_info`
       FROM `productinfo`
       INNER JOIN `productinfo_tags` ON ( `productinfo_tags`.`productinfo_id` = `productinfo`.`id` )
       INNER JOIN `test_tag` ON ( `test_tag`.`id` = `productinfo_tags`.`tag_id` )
       INNER JOIN `test_usertagging` ON ( `test_usertagging`.`tag_id` = `test_tag`.`id` )
    WHERE
       (`test_usertagging`.`user_id` IN (1,2,3,4 ... ) AND
        `productinfo`.`product_id` IN ('abc', 'def', '000', '111', ...));
格式化的查询:

SELECT test_usertagging.user_id,
       test_usertagging.tag_id,
       test_usertagging.extra_info
  FROM productinfo
  JOIN productinfo_tags ON productinfo_tags.productinfo_id = productinfo.id
  JOIN test_tag ON test_tag.id = productinfo_tags.tag_id
  JOIN test_usertagging ON test_usertagging.tag_id = test_tag.id
 WHERE test_usertagging.user_id IN (1,2,3,4 ... )
   AND productinfo.product_id IN ('abc', 'def', '000', '111', ...)
我得到的是:

+----+-------------+------------------+--------+------------------------------------------------------------------+------------------------------+---------+--------------------------------------+------+---    -----------------------+
| id | select_type | table            | type   | possible_keys                                                    | key                          | key_len | ref                                  | rows |     Extra                    |
+----+-------------+------------------+--------+------------------------------------------------------------------+------------------------------+---------+--------------------------------------+------+---    -----------------------+
|  1 | SIMPLE      | productinfo      | range  | PRIMARY,productinfo_218f3960                                       | productinfo_218f3960      | 62      | NULL                                |   55 | Using     where; Using index |
|  1 | SIMPLE      | productinfo_tags | ref    | productinfo_id,productinfo_tags_4b5946a2,productinfo_tags_5659cca2 | productinfo_id            | 4       | tookyo_prod.productinfo.id          |    1 | Using     index              |
|  1 | SIMPLE      | test_tag         | eq_ref | PRIMARY                                                            | PRIMARY                   | 4       | tookyo_prod.productinfo_tags.tag_id |    1 | Using     index              |
|  1 | SIMPLE      | test_usertagging | ref    | test_usertagging_5659cca2                                          | test_usertagging_5659cca2 | 4       | tookyo_prod.productinfo_tags.tag_id |  217 | Using where              |
+----+-------------+---------------------+--------+------------------------------------------------------------------+------------------------------+---------+--------------------------------------+------+--------------------------+
此查询执行得很差。困扰我的是最后一行的“使用where”(不带索引)(test_usertagging)——正确的索引列在
键下,但仍然显示“使用where”

我曾尝试添加
强制索引
,但这并没有改善问题(因为正确的索引已经列出)

使用
直联
只需更改最后两行之间的顺序。(请注意,
test_标记
表本身对此查询是多余的;完全删除它不会改变任何内容)

关于如何使用相关可用索引(
user\u id
tag\u id
)中的一个或两个,从
test\u usertagging
进行查询,您知道吗

以下是连接表的
SHOW CREATE TABLE
输出:

CREATE TABLE `test_usertagging` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tag_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `usertagging_user_per_tag_is_unique` (`user_id`,`tag_id`),
  KEY `test_usertagging_5659cca2` (`tag_id`),
  CONSTRAINT `test_usertagging_ibfk_3` FOREIGN KEY (`tag_id`) REFERENCES `test_tag` (`id`),
  CONSTRAINT `test_usertagging_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `test_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6456921 DEFAULT CHARSET=utf8

CREATE TABLE `productinfo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` varchar(20) NOT NULL,
  `text` varchar(256) NOT NULL,
  `inftype` varchar(64) NOT NULL,
  `extra_info` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `productinfo_218f3960` (`product_id`),
  CONSTRAINT `product_id_refs_rpk_d9184c73` FOREIGN KEY (`product_id`) REFERENCES `product` (`rpk`)
) ENGINE=InnoDB AUTO_INCREMENT=44088 DEFAULT CHARSET=utf8

CREATE TABLE `productinfo_tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `productinfo_id` int(11) NOT NULL,
  `tag_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `productinfo_id` (`productinfo_id`,`tag_id`),
  KEY `productinfo_tags_4b5946a2` (`productinfo_id`),
  KEY `productinfo_tags_5659cca2` (`tag_id`),
  CONSTRAINT `productinfo_id_refs_id_1c393f74` FOREIGN KEY (`productinfo_id`) REFERENCES `productinfo` (`id`),
  CONSTRAINT `tag_id_refs_id_0afa07dc` FOREIGN KEY (`tag_id`) REFERENCES `test_tag` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=62637 DEFAULT CHARSET=utf8

在典型的多对多映射表中,例如
test\u usertaging
productinfo\u tags
,通常不需要
id自动递增主键。去掉该列,并将复合
UNIQUE
键提升为
主键

这种改变可能会加快一个方向,因为通过PK进行查找的速度大约是通过辅助键进行查找的速度的两倍


您的标题谈论的是
外键
,而实际上,索引才是最重要的。(如果FK不存在,它将创建一个索引。)

您在“显示创建表”中又错过了一个表。由于(1,2,3,4…)中的
test\u usertagging
user\u id
,您将获得“using where”。MySQL加入表,然后检查此条件以满足以下要求:如果您将(1,2,3,4…)中的
WHERE test\u usertagging.user\id重铸为
WHERE test\u usertagging.user\id介于1和19之间的
或类似内容,您将使该搜索词可搜索。此外,EXPLAIN输出中的行数也不是很大。每个表中有多少行?你有什么表演?您需要什么性能?@SamIvichuk但它不能使用用户id上的索引来检查较少的行吗?@OllieJones不幸的是,实际上这些是任意数字(用户id),不是连续的。这些表并不小,它们有10万到数百万行。这里给出的行数是MySQL对匹配行的估计。查询需要几分钟(例如3分钟)。我希望正确的实现可以在几秒钟内完成,我想20秒是可以接受的