0

How to fasten up the %like search? I need help. Idea 1= limit, idea 2= split comma keywords to seperate columns

  1. It is a comma seperated keyword list.
  2. After 1000 results the search query could stop, to fasten the search query (how?).
  3. If i could use a limit, i need to let the search query start with the "best rated products" = "rating" and stop after around 1000 results (how?).
  4. my search query: replace(b.keywords,',',' ') like '% ".$searchvalue."%')";

My idea (1) is to limit the results to 1000. But how can I control the select so that the products with the best rating are searched first and will not be missed. As soon as 1000 (max) are found, the query should stop. But the best-rated products should be searched first or will be missed. After 1000 results the search query should stop, to fasten the search query.

I have a table PRODUCTS. A RATING from 0 up to 10.000.

ID     RATING PRODUCTS   KEYWORDS
1      1000      p1      keyword1,keyword2,...,keyword100
...    4         ...     ...  
99000  200       p99000  keyword1,keyword99,...,keyword999

"Rating" and "keywords" (multilingual) are changing from time to time.

My idea (2) is to seperate each keyword in a single column. So i would not need the leading % $searchvalue%. But iam worried, there will be at least 200 additional columns for each product and this will result in the same slowly search query (?). What do you think?

ID     RATING PRODUCTS   KEYWORD1 KEYWORD2 KEYWORD3 ... KEYWORD**200** 
1      1000      p1      red      blue     yellow   ... yellow-orange
...    4         ...     ...  
99000  200       p99000  black    blue     orange   ... yellow-orange
babawo
  • 5
  • 4
  • 1
    Don't use comma-separated lists in the first place. Normalize your table and make a separate `product_keywords` table with a separate row for each keyword. – Barmar Nov 03 '20 at 03:43
  • sadly they keywords area changing daily and are user generated too and multilingual, they keyword list would be too long. english ,french, german, russia, .. I could make a keyword list in english only and translate a seach query, but it is too expensive to translate all search queries. :( – babawo Nov 03 '20 at 03:46
  • How are you going to do translations with either of your designs? – Barmar Nov 03 '20 at 03:47
  • @barmar user generated keywords are checked and translated offline (copy paste) and added after to the keywords comma list, for each product. At the moment, english ,french,german,russia,spanish – babawo Nov 03 '20 at 03:49
  • 1
    Searching the comma-separated list will be really slow, it can't be indexed. – Barmar Nov 03 '20 at 03:52
  • @babawo When you say that having a table for keywords would make the "keyword list too long", what do you mean by that? Mysql can handle millions of rows in a table without any trouble. – Cully Nov 03 '20 at 04:03
  • @cully ok, think you are right. – babawo Nov 03 '20 at 04:07
  • What do you mean by "fasten"? Do you mean "speed up"? – Barmar Nov 03 '20 at 15:34
  • @Barmar Yes, sorry. – babawo Nov 03 '20 at 16:10

1 Answers1

0

Use a separate table product_keywords.

CREATE TABLE product_keywords (
    product_id INT NOT NULL,
    keyword VARCHAR(50) NOT NULL,
    FOREIGN KEY (product_id) REFEREFENCES products (id),
    UNIQUE INDEX (product_id, keyword)
);

Join with this table to find the products that match a keyword.

If you need multilingual keyword support, you can replace keyword with a foreign key to a table with keywords, and that table can contain keywords in multiple languages.

CREATE TABLE keywords (
    id INT NOT NULL,
    language VARCHAR(10),
    keyword VARCHAR(50),
    UNIQUE KEY (id, language),
    INDEX (keyword, language)
);

CREATE TABLE product_keywords (
    product_id INT NOT NULL,
    keyword_id INT NOT NULL,
    FOREIGN KEY (product_id) REFEREFENCES products (id),
    FOREIGN KEY (keyword_id) REFERENCES keywords (id),
    UNIQUE INDEX (product_id, keyword_id)
);

A query might then look like

SELECT p.*
FROM products AS p
JOIN product_keywords AS pk ON p.id = pk.product_id
JOIN keywords AS k on k.id = pk.keyword_id
WHERE k.language = 'en' AND k.keyword = 'blue'
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I think your answer is pretty good. May I ask you how I can convert the current database? First I have to normalize the comma list and get rid of white spaces and then .. select keyword1.. keyword2,.. insert ignore ..? – babawo Nov 03 '20 at 04:24
  • See https://stackoverflow.com/questions/17942508/sql-split-values-to-multiple-rows – Barmar Nov 03 '20 at 06:02
  • i looked at this. It is generating an additional ID per keyword. Looking for, but can`t find, 1 keyword and all IDs combined. Did I misunderstand that? PRODUCT_ID 1,22,99000 – babawo Nov 03 '20 at 07:02
  • You should post a new question showing what you tried and the results. – Barmar Nov 03 '20 at 07:05
  • i did it, and :( this happened, i know its bad, what`s why iam doing this right now, who does block questions here? Strange.: This question already has answers here: Is storing a delimited list in a database column really that bad? (10 answers) – babawo Nov 03 '20 at 08:15
  • @Barmer i converted the database but my first test-queries result in multiple same results, because there are "red car" and "red". This will display 2 results of the same product_id. any idea how to solve this? – babawo Nov 04 '20 at 17:36
  • edit for comment above: select b.id_parent,b.viewed as aviewed,'photos' as tbl from photos b JOIN product_keywords u ON b.id_parent = u.product_id WHERE b.published=1 and (replace(u.keyword,',',' ') like '%red%' or replace(u.keyword,',',' ') like '%red%') – babawo Nov 04 '20 at 17:37
  • I think your rate of questions may be limited by your reputation. – Barmar Nov 04 '20 at 18:11
  • Don't use `LIKE` if you don't want multiple matches, use `=`. – Barmar Nov 04 '20 at 18:12
  • Or use `SELECT DISTINCT` to remove duplicate results. – Barmar Nov 04 '20 at 18:12