Hello,
When working on T17441 we decided to start converting UNIQUE keys into PK as those are easy should be fine to convert. We converted a bunch of tables, including pagelinks and template links. Only one slave per shard to see how it would do. So this is how the shard is (note the UNIQUE KEY):
root@PRODUCTION s6[frwiki]> select @@hostname; +------------+ | @@hostname | +------------+ | db1088 | +------------+ 1 row in set (0.00 sec) root@PRODUCTION s6[frwiki]> show create table templatelinks\G show create table pagelinks\G *************************** 1. row *************************** Table: templatelinks Create Table: CREATE TABLE `templatelinks` ( `tl_from` int(8) unsigned NOT NULL DEFAULT '0', `tl_namespace` int(11) NOT NULL DEFAULT '0', `tl_title` varbinary(255) NOT NULL DEFAULT '', `tl_from_namespace` int(11) NOT NULL DEFAULT '0', UNIQUE KEY `tl_from` (`tl_from`,`tl_namespace`,`tl_title`), KEY `tl_namespace` (`tl_namespace`,`tl_title`,`tl_from`), KEY `tl_backlinks_namespace` (`tl_from_namespace`,`tl_namespace`,`tl_title`,`tl_from`) ) ENGINE=InnoDB DEFAULT CHARSET=binary 1 row in set (0.00 sec) *************************** 1. row *************************** Table: pagelinks Create Table: CREATE TABLE `pagelinks` ( `pl_from` int(8) unsigned NOT NULL DEFAULT '0', `pl_namespace` int(11) NOT NULL DEFAULT '0', `pl_title` varbinary(255) NOT NULL DEFAULT '', `pl_from_namespace` int(11) NOT NULL DEFAULT '0', UNIQUE KEY `pl_from` (`pl_from`,`pl_namespace`,`pl_title`), KEY `pl_namespace` (`pl_namespace`,`pl_title`,`pl_from`), KEY `pl_backlinks_namespace` (`pl_from_namespace`,`pl_namespace`,`pl_title`,`pl_from`) ) ENGINE=InnoDB DEFAULT CHARSET=binary 1 row in set (0.00 sec)
And this is how we left db1093 (only that host) (note the PRIMARY KEY - also, note that the tl_from and pl_from indexes were added yesterday to fix the issue described below)
root@db1093[frwiki]> select @@hostname; +------------+ | @@hostname | +------------+ | db1093 | +------------+ 1 row in set (0.01 sec) root@db1093[frwiki]> show create table templatelinks\G show create table pagelinks\G *************************** 1. row *************************** Table: templatelinks Create Table: CREATE TABLE `templatelinks` ( `tl_from` int(8) unsigned NOT NULL DEFAULT '0', `tl_namespace` int(11) NOT NULL DEFAULT '0', `tl_title` varbinary(255) NOT NULL DEFAULT '', `tl_from_namespace` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`tl_from`,`tl_namespace`,`tl_title`), KEY `tl_namespace` (`tl_namespace`,`tl_title`,`tl_from`), KEY `tl_backlinks_namespace` (`tl_from_namespace`,`tl_namespace`,`tl_title`,`tl_from`), KEY `tl_from` (`tl_from`,`tl_namespace`,`tl_title`) ) ENGINE=InnoDB DEFAULT CHARSET=binary 1 row in set (0.00 sec) *************************** 1. row *************************** Table: pagelinks Create Table: CREATE TABLE `pagelinks` ( `pl_from` int(8) unsigned NOT NULL DEFAULT '0', `pl_namespace` int(11) NOT NULL DEFAULT '0', `pl_title` varbinary(255) NOT NULL DEFAULT '', `pl_from_namespace` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`pl_from`,`pl_namespace`,`pl_title`), KEY `pl_namespace` (`pl_namespace`,`pl_title`,`pl_from`), KEY `pl_backlinks_namespace` (`pl_from_namespace`,`pl_namespace`,`pl_title`,`pl_from`), KEY `pl_from` (`pl_from`,`pl_namespace`,`pl_title`) ) ENGINE=InnoDB DEFAULT CHARSET=binary 1 row in set (0.00 sec)
We converted one slave per host, and we have seen that there were some issues with db1093 (s6, frwiki,jawiki,ruwiki) with two specific queries, which were doing a FORCE index:
pagelinks table
ApiQueryLinks::run 10.64.48.152 1176 Key 'pl_from' doesn't exist in table 'pagelinks' (10.64.48.152) SELECT pl_from,pl_namespace,pl_title FROM `pagelinks` FORCE INDEX (pl_from) WHERE pl_from = 'xx' AND pl_namespace = '0' ORDER BY pl_title LIMIT 501
And templatelinks table
ApiQueryLinks::run 10.64.48.152 1176 Key 'tl_from' doesn't exist in table 'templatelinks' (10.64.48.152) SELECT tl_from AS `pl_from`,tl_namespace AS `pl_namespace`,tl_title AS `pl_title` FROM `templatelinks` FORCE INDEX (tl_from) WHERE tl_from IN (xxx) AND ((tl_namespace = 'xx' AND tl_title IN ('xx') )) ORDER BY tl_from,tl_namespace,tl_title LIMIT 501
The way we fixed this was to create an index with that same name (and with the columns it originally had) as specified above.
However, the ideal fix would be to remove that FORCE index there and let MySQL use the correct index for it.
I found this (from 2008) which might be related to why the FORCE is being used there: https://phabricator.wikimedia.org/rMWba0f2974df812bc6e1f9e7972b616ed5b9d689f0#6d708370 and https://phabricator.wikimedia.org/rMWe26e924557e591359a633c0f063bdc7f35e0bc34
Almost 10 years have passed by so maybe the error that was found at the time is solved already with all the improvements made to the optimizer. Otherwise it is going to be difficult to get rid of UNIQUE keys that are being used because of those FORCE
Thanks
Note: If the tags I have used, specially MediaWiki-API isn't correct, please feel free to change them or let me know