0

I have these 4 different tables as below.

First is the companyCategory. This is table keep all the different categories of companies

CREATE TABLE `companyCategory` (
  `companyCategoryID` int NOT NULL,
  `companyCategory` varchar(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT;



ALTER TABLE `companyCategory`
  ADD PRIMARY KEY (`companyCategoryID`);
ALTER TABLE `companyCategory` ADD FULLTEXT KEY `companyCategory` (`companyCategory`);

Second table is the company.

   CREATE TABLE `company` (
      `companyID` smallint NOT NULL,
      `segmentID` tinyint NOT NULL DEFAULT '1',
      `companyCategoryID` tinyint NOT NULL,
      `companyName` varchar(50) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
      `companyNumber` varchar(15) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
      `contactPerson` varchar(20) NOT NULL,
      `companyAddress` varchar(70) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`companyLatitude` float(10,8) NOT NULL,
`companyLongitude` float(11,8) NOT NULL,
      `companyContactNumber` varchar(15) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
      `companyEmail` varchar(35) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
      `companyDescription` varchar(50) DEFAULT NULL,
      `companyTimeZoneID` tinyint UNSIGNED NOT NULL,  
      `companyInsertUserID` mediumint DEFAULT NULL,
      `companyStatus` enum('a','d') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;



    ALTER TABLE `company`
      ADD PRIMARY KEY (`companyID`),
      ADD UNIQUE KEY `companyNameIndex` (`companyName`);
    ALTER TABLE `company` ADD FULLTEXT KEY `companyName` (`companyName`);

Third table is itemCategory.

CREATE TABLE `itemCategory` (
  `itemCategoryID` smallint UNSIGNED NOT NULL,
  `companyID` smallint UNSIGNED NOT NULL,
  `itemCategory` varchar(35) NOT NULL,
  `itemCategoryStatus` enum('a','d') NOT NULL,
  `userID` mediumint NOT NULL,
  `dateTimeInsert` timestamp NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;



ALTER TABLE `itemCategory`
  ADD PRIMARY KEY (`itemCategoryID`),
  ADD UNIQUE KEY `companyID` (`companyID`,`itemCategory`);
ALTER TABLE `itemCategory` ADD FULLTEXT KEY `itemCategory` (`itemCategory`);

Fourth table is

CREATE TABLE `item` (
  `itemID` smallint NOT NULL,
  `itemCategoryID` smallint NOT NULL,
  `companyID` smallint NOT NULL,
  `itemName` varchar(35) NOT NULL,
  `itemDescription` varchar(50) DEFAULT NULL,
  `itemPrice` decimal(5,2) NOT NULL,
  `itemStatus` enum('a','d') NOT NULL,
  `userID` smallint NOT NULL,
  `dateTimeInsert` timestamp NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;



ALTER TABLE `item`
  ADD PRIMARY KEY (`itemID`),
  ADD UNIQUE KEY `companyID` (`companyID`,`itemName`);
ALTER TABLE `item` ADD FULLTEXT KEY `itemName` (`itemName`);

Now my challenge is that I have enable Fulltext on each of these table. The first link is between company and companyCategory based on companyCategoryID.

Next the link between itemCategory and item based on the itemCategoryID. Both these table also have companyID as it links to the company table. Now my challenge is say user put a key word.

The keyword can be search across all these table. Below is the query which I have tested. When I run explain it does not show the fullindex is being used. At minimal it should the company name if it match the company name or companyCategory. Next level if it matches the item category or item only if there is item is matching

select company.companyID,item.itemName

FROM company

JOIN companyCategory ON
company.companyCategoryID=companyCategory.companyCategoryID
JOIN itemCategory ON
company.companyID = itemCategory.companyID
JOIN item ON
company.companyID = item.companyID
WHERE

MATCH(company.companyName) AGAINST('*foo*' IN BOOLEAN MODE)
OR MATCH(companyCategory.companyCategory) AGAINST('*foo*' IN BOOLEAN MODE)
OR MATCH(itemCategory.itemCategory) AGAINST('*foo*' IN BOOLEAN MODE)
OR MATCH(item.itemName) AGAINST('*foo*' IN BOOLEAN MODE)

Here is my new version of the query with union new solution.

SELECT  allValue.cm AS cName,allValue.companyID AS cID,allValue.companyCategory As cCategory,(allValue.distance/1000) as distance
                        FROM  ( 
                                (select item.itemName as itemName,null,company.companyName as cm,company.companyID as companyID,companyCategory.companyCategory,ST_Distance_Sphere( ST_GeomFromText(:userPoint1a), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) as distance
                                From item
                                JOIN company ON
                                item.companyID=company.companyID
                                JOIN companyCategory ON 
                                companyCategory.companyCategoryID = company.companyCategoryID 
                                WHERE                         
                                MATCH(item.itemName) AGAINST(:searchKey1 IN BOOLEAN MODE) AND ST_Distance_Sphere( ST_GeomFromText(:userPoint1b), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) < 200000
                                )

                                UNION DISTINCT

                                (
                                select null,null,company.companyName as cm,company.companyID as companyID,companyCategory.companyCategory,ST_Distance_Sphere( ST_GeomFromText(:userPoint2a), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) as distance
                                From company 
                                JOIN companyCategory ON
                                companyCategory.companyCategoryID=company.companyCategoryID          
                                WHERE                         
                                MATCH(company.companyName) AGAINST(:searchKey2 IN BOOLEAN MODE) AND ST_Distance_Sphere( ST_GeomFromText(:userPoint2b), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) < 200000
                                )

                                UNION DISTINCT

                                (
                                select null,null,company.companyName as cm,company.companyID as companyID,companyCategory.companyCategory,ST_Distance_Sphere( ST_GeomFromText(:userPoint3a), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) as distance
                                From itemCategory
                                JOIN company ON
                                itemCategory.companyID=company.companyID
                                JOIN companyCategory ON
                                companyCategory.companyCategoryID=company.companyCategoryID
                                WHERE                         
                                MATCH(itemCategory.itemCategory) AGAINST(:searchKey3 IN BOOLEAN MODE) AND ST_Distance_Sphere( ST_GeomFromText(:userPoint3b), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) < 200000
                                )

                                UNION DISTINCT

                                (
                                select null,null,company.companyName as cm,company.companyID as companyID,companyCategory.companyCategory,ST_Distance_Sphere( ST_GeomFromText(:userPoint4a), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) as distance
                                From companyCategory
                                JOIN company ON
                                companyCategory.companyCategoryID=company.companyCategoryID
                                WHERE 
                                MATCH(companyCategory.companyCategory) AGAINST(:searchKey4 IN BOOLEAN MODE) AND ST_Distance_Sphere( ST_GeomFromText(:userPoint4b), ST_GeomFromText(CONCAT('POINT(', company.companyLongitude, ' ', company.companyLatitude, ')'))) < 200000
                                )
                        ) As allValue Group By allValue.companyID,allValue.cm,allValue.companyCategory,allValue.distance

1 Answer 1

1

The performance will probably be terrible. FULLTEXT shines when one MATCH in one table. It is not designed for what you are doing.

Plan A: Don't use FT for simple tests on what is usually a single word.

Plan B: Toss all the words into a column in a single table; then use single MATCH on that.

Further notes...

Sure, you might not have the exact name for a "company" or "item", but FT only helps with some fuzzy queries. LIKE "foo%" also helps only some, but might be better for your situation. (Note that does not have a leading wildcard.)

FT shines with long prose where you don't know where the desired keyword is.

For the UNION version, use UNION ALL unless you are expecting duplicates and need to avoid them.

15
  • so in this case since I need to be able to search across different tables what is your best suggestions? Will union between different single queries help though? I think your plan B difficult to work cause they are all different tables with different functions
    – newbie
    Commented Apr 8, 2020 at 15:08
  • UNION is almost always better than OR. So, sure, see if that helps enough.
    – Rick James
    Commented Apr 8, 2020 at 15:53
  • So if unions will that be efficient enough?
    – newbie
    Commented Apr 8, 2020 at 16:07
  • @newbie - Try it.
    – Rick James
    Commented Apr 9, 2020 at 5:00
  • I have updated my question at the last part I have added the new query that is the union part. Can you give me your opinion if this optimise or it can be further optimise?
    – newbie
    Commented Apr 16, 2020 at 17:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.