InnoDB supports secondary indexes on virtual generated columns.
https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html
In 5.7(onward) you can use a generated column, then index that column. e.g.
Here is an example of taking the integer out of the string to create an efficient join:
CREATE TABLE myusers (
id mediumint(8) unsigned NOT NULL auto_increment
, name varchar(255) default NULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1
;
INSERT INTO myusers (`name`) VALUES ('Imelda'),('Hamish'),('Brandon'),('Amity'),('Jillian'),('Lionel'),('Faith'),('Dai'),('Reed'),('Molly');
CREATE TABLE mytable (
id mediumint(8) unsigned NOT NULL auto_increment
, user_id VARCHAR(20)
, ex_user_id integer GENERATED ALWAYS AS (0+substring(user_id,6,20))
, password varchar(255)
, PRIMARY KEY (`id`)
, INDEX idx_ex_user_id (ex_user_id)
) AUTO_INCREMENT=1
;
INSERT INTO mytable (`user_id`,`password`) VALUES
('user_1','PYX68BIC9RD')
,('user_2','LPY07EIN0UA')
,('user_3','UGC24TKI3JL')
,('user_4','YQU18ALB8YA')
,('user_5','DEL56AGR6AD')
,('user_6','YQN87UOB0PO')
,('user_7','CPC15JFU6MC')
,('user_8','MWC40ZWD2EE')
,('user_9','HEB34QQH0UM')
,('user_10','GVP36PLP5PW')
;
select
*
from myusers
inner join mytable on myusers.id = mytable.ex_user_id
;
id | name | id | user_id | ex_user_id | password
-: | :------ | -: | :------ | ---------: | :----------
1 | Imelda | 1 | user_1 | 1 | PYX68BIC9RD
2 | Hamish | 2 | user_2 | 2 | LPY07EIN0UA
3 | Brandon | 3 | user_3 | 3 | UGC24TKI3JL
4 | Amity | 4 | user_4 | 4 | YQU18ALB8YA
5 | Jillian | 5 | user_5 | 5 | DEL56AGR6AD
6 | Lionel | 6 | user_6 | 6 | YQN87UOB0PO
7 | Faith | 7 | user_7 | 7 | CPC15JFU6MC
8 | Dai | 8 | user_8 | 8 | MWC40ZWD2EE
9 | Reed | 9 | user_9 | 9 | HEB34QQH0UM
10 | Molly | 10 | user_10 | 10 | GVP36PLP5PW
explain select
*
from myusers
inner join mytable on myusers.id = mytable.ex_user_id
;
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
-: | :---------- | :------ | :--------- | :--- | :------------- | :------------- | :------ | :------------------------------------- | ---: | -------: | :----------
1 | SIMPLE | myusers | null | ALL | PRIMARY | null | null | null | 10 | 100.00 | null
1 | SIMPLE | mytable | null | ref | idx_ex_user_id | idx_ex_user_id | 5 | fiddle_HNTHMETRTFAHHKBIGWZM.myusers.id | 1 | 100.00 | Using where
db<>fiddle here
note the conversion of user_id from string to integer is "implicit":
To cast a string to a number, you normally need do nothing other than use the string value in numeric context:
https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html
t2.user_idso that it does NOT require a constant prefix ofUSER_which adds no benefits but does deliver disadvantages.t2.user_idshould be an integer, not a string