** Edited 11/10 **
Broke down and started fiddling myself with this. After a bit of research and testing I've put together this set of queries which hopefully will help shed some additional light. (I used dbfiddle. Note the queries that fail are commented out because nothing else will run if left in, at least on dbfiddle.)
Try running these, hopefully the output and comments will best explain. In particular, Query Set 7 & 8 show how to setup the multi-column FULLTEXT INDEX, as I think this may be your ultimate intention here.
-------------------------------- Query Set 1 ------------------------------------
-- Only possible key is `idcategory`, because each FULLTEXT INDEX is for a single
-- column, but using 3 different MATCH clauses, each for a different column.
-- (i.e. Can't index into all 3 simultaneously using only a single column index.)
-- Keys/Indexes on `idcategory`.
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idcategory` bigint(20) NOT NULL,
`name` text NOT NULL,
`short_description` text,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`),
FULLTEXT INDEX `name_fulltext` (`name`),
FULLTEXT INDEX `short_description_fulltext` (`short_description`),
FULLTEXT INDEX `description_fulltext` (`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
EXPLAIN SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
OR MATCH(p.short_description) AGAINST ("*test*" IN BOOLEAN MODE)
OR MATCH(p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);
SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
OR MATCH(p.short_description) AGAINST ("*test*" IN BOOLEAN MODE)
OR MATCH(p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);
-------------------------------- Query Set 2 ------------------------------------
-- Possible keys are `idcategory` and `name_fulltext`. All FULLTEXT INDEXES are
-- single column, and only 1 MATCH clause [for a single column, `name`] is
-- specified. Keys/Indexes on `name_fulltext`. (When faced with a choice of
-- multiple indexes, the optimizer will choose the most selective option [i.e.
-- that option with the lowest number of rows]).
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idcategory` bigint(20) NOT NULL,
`name` text NOT NULL,
`short_description` text,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`),
FULLTEXT INDEX `name_fulltext` (`name`),
FULLTEXT INDEX `short_description_fulltext` (`short_description`),
FULLTEXT INDEX `description_fulltext` (`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
EXPLAIN SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
);
SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
);
-------------------------------- Query Set 3 ------------------------------------
-- Same as Query Set 2, but explicitly call for INDEX `name_fulltext`. Now only
-- possible key is name_fulltext.
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idcategory` bigint(20) NOT NULL,
`name` text NOT NULL,
`short_description` text,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`),
FULLTEXT INDEX `name_fulltext` (`name`),
FULLTEXT INDEX `short_description_fulltext` (`short_description`),
FULLTEXT INDEX `description_fulltext` (`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
EXPLAIN SELECT *
FROM products AS p USE INDEX (`name_fulltext`)
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
);
SELECT *
FROM products AS p USE INDEX (`name_fulltext`)
WHERE p.idcategory = 1
AND (
MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
);
-------------------------------- Query Set 4 ------------------------------------
----------------------------------- FAILS ---------------------------------------
-- Same as Query Set 1 but trying to force INDEX `name_fulltext`. Doesn't work
-- because `name_fulltext` only indexes a single column, but MATCH / AGAINST
-- has three different clauses, each specifying a different column. (And hence
-- why the only possible key is `idcategory`, as shown in output of EXPLAIN,
-- Query Set 1.)
--DROP TABLE IF EXISTS `products`;
--CREATE TABLE `products` (
-- `id` bigint(20) NOT NULL AUTO_INCREMENT,
-- `idcategory` bigint(20) NOT NULL,
-- `name` text NOT NULL,
-- `short_description` text,
-- `description` longtext NOT NULL,
-- PRIMARY KEY (`id`),
-- KEY `idcategory` (`idcategory`),
-- FULLTEXT INDEX `name_fulltext` (`name`),
-- FULLTEXT INDEX `short_description_fulltext` (`short_description`),
-- FULLTEXT INDEX `description_fulltext` (`description`)
--) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
--VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
--EXPLAIN SELECT *
--FROM products AS p USE INDEX (`name_fulltext`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
-- OR MATCH(p.short_description) AGAINST ("*test*" IN BOOLEAN MODE)
-- OR MATCH(p.description) AGAINST ("*test*" IN BOOLEAN MODE)
--);
--SELECT *
--FROM products AS p USE INDEX (`name_fulltext`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
-- OR MATCH(p.short_description) AGAINST ("*test*" IN BOOLEAN MODE)
-- OR MATCH(p.description) AGAINST ("*test*" IN BOOLEAN MODE)
--);
-------------------------------- Query Set 5 ------------------------------------
----------------------------------- FAILS ---------------------------------------
-- Trying to force keying/indexing on `idcategory` instead of `name_fulltext`.
-- Doesn't work because `idcategory` is not established as a FULLTEXT INDEX,
-- which is required for MATCH / AGAINST? It keyed on this field when not
-- explicitly calling USE INDEX and no other index was possible, and when
-- explicitly calling USE INDEX but with no MATCH / AGAINST call, so
-- this behavior seems a bit inconsistent.
--DROP TABLE IF EXISTS `products`;
--CREATE TABLE `products` (
-- `id` bigint(20) NOT NULL AUTO_INCREMENT,
-- `idcategory` bigint(20) NOT NULL,
-- `name` text NOT NULL,
-- `short_description` text,
-- `description` longtext NOT NULL,
-- PRIMARY KEY (`id`),
-- KEY `idcategory` (`idcategory`),
-- FULLTEXT INDEX `name_fulltext` (`name`),
-- FULLTEXT INDEX `short_description_fulltext` (`short_description`),
-- FULLTEXT INDEX `description_fulltext` (`description`)
--) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
--VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
--EXPLAIN SELECT *
--FROM products AS p USE INDEX (`idcategory`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
--);
--SELECT *
--FROM products AS p USE INDEX (`idcategory`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
--);
-------------------------------- Query Set 6 ------------------------------------
----------------------------------- FAILS ---------------------------------------
-- We can't make `idcategory` a FULLTEXT INDEX of course, because it is a
-- bigint(20). (Could try making this KEY a text field instead,
-- see if error persists...)
--DROP TABLE IF EXISTS `products`;
--CREATE TABLE `products` (
-- `id` bigint(20) NOT NULL AUTO_INCREMENT,
-- `idcategory` bigint(20) NOT NULL,
-- `name` text NOT NULL,
-- `short_description` text,
-- `description` longtext NOT NULL,
-- PRIMARY KEY (`id`),
-- KEY `idcategory` (`idcategory`),
-- FULLTEXT INDEX `idcategory_fulltext` (`idcategory`)
--) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
--VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
--EXPLAIN SELECT *
--FROM products AS p USE INDEX (`idcategory`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
--);
--SELECT *
--FROM products AS p USE INDEX (`idcategory`)
--WHERE p.idcategory = 1
--AND (
-- MATCH(p.name) AGAINST ("*test*" IN BOOLEAN MODE)
--);
-------------------------------- Query Set 7 ------------------------------------
-- A multi-column index. The MATCH / AGAINST search functions like an 'OR'
-- clause for all three columns. (i.e. if the text pattern is present in any
-- of the three columns, a match is found). Must specify all three columns in MATCH
-- clause, because the FULLTEXT INDEX includes all three.
-- Keys/Indexes on 'name_sdesc_desc_fulltext` (multi-column fulltext index),
-- but shows `idcategory` as possible index.
-- (Perhaps when all is said and done this is the desired behavior?)
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idcategory` bigint(20) NOT NULL,
`name` text NOT NULL,
`short_description` text,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`),
FULLTEXT INDEX `name_sdesc_desc_fulltext` (`name`, `short_description`, `description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
EXPLAIN SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name, p.short_description, p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);
SELECT *
FROM products AS p
WHERE p.idcategory = 1
AND (
MATCH(p.name, p.short_description, p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);
-------------------------------- Query Set 8 ------------------------------------
-- Same as Query Set 7, but explicitly calls for `name_sdesc_desc` FULLTEXT INDEX.
-- Now, only possible index is `name_sdesc_desc_fulltext`.
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idcategory` bigint(20) NOT NULL,
`name` text NOT NULL,
`short_description` text,
`description` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`),
FULLTEXT INDEX `name_sdesc_desc_fulltext` (`name`, `short_description`, `description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` (`idcategory`, `name`, `short_description`, `description`)
VALUES (1, 'test1', 'sdesc1', 'desc1'), (1, 'test2', 'sdesc2', 'desc2'), (2, 'test3', 'sdesc3', 'desc3');
EXPLAIN SELECT *
FROM products AS p USE INDEX (`name_sdesc_desc`)
WHERE p.idcategory = 1
AND (
MATCH(p.name, p.short_description, p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);
SELECT *
FROM products AS p USE INDEX (`name_sdesc_desc`)
WHERE p.idcategory = 1
AND (
MATCH(p.name, p.short_description, p.description) AGAINST ("*test*" IN BOOLEAN MODE)
);