Reputation: 2597
I have a items
table with category_id
field.
There is a specific rule to order the items by category_id
.
I usually sort the data like this:
SELECT * FROM items ORDER BY FIELD(category_id, 2, 5, 1, 4, 3)
-- In this example, the "rule" is sorting in order of (2, 5, 1, 4, 3)
In this case, simply creating an index on category_id
field does not work to speed up sorting items, because the index sorts the category_id just ascending like (1, 2, 3, 4, 5).
Is it possible to specify the sorting rule when I CREATE INDEX
on category_id field?
(And then simply SELECT * FROM items ORDER BY category_id
works)
Or do I have to create another field like sorted_category_id
which is sorted according to the order rule?
Upvotes: 0
Views: 1222
Reputation: 350770
Adding the column to the items
table, with an index on it, would indeed be a solution focused on speed. By making it a generated column, you ensure consistency, and by making it a virtual column, you can move the extra data into an index (if you create it). So proceed like this:
ALTER TABLE items ADD (
category_ord int GENERATED ALWAYS AS (FIELD(category_id, 2, 5, 1, 4, 3)) VIRTUAL
);
CREATE INDEX idx_items_category_ord ON items(category_ord);
SELECT * FROM items ORDER BY category_ord;
Alternatively, the normalised way is to add a column to the category
table. This will have a slight performance impact if you have many categories, but does not pose that consistency problem, and saves space. To implement that idea, proceed as follows:
If you don't have that category
table, then create it:
CREATE TABLE category(
id int NOT NULL PRIMARY KEY,
ord int NOT NULL,
name varchar(100)
);
Populate the ord
field (or whatever you want to call it) as desired:
INSERT INTO category(id, ord, name) VALUES
(1, 30, 'cat1'),
(2, 10, 'cat2'),
(3, 50, 'cat3'),
(4, 40, 'cat4'),
(5, 20, 'cat5');
And add an index on the ord
column:
CREATE INDEX category_ord ON category(ord);
Now the query would be:
SELECT *
FROM items
INNER JOIN category
ON items.category_id = category.id
ORDER BY category.ord;
The database engine can now decide to use the index on the ord
column (or not), depending on its own analysis. If you want to force the use of it, you can use FORCE INDEX
:
SELECT *
FROM items
INNER JOIN category FORCE INDEX category(category_ord)
ON items.category_id = category.id
ORDER BY category.ord;
Note that the engine can use your index on the items.category_id
as well, for value by value lookup.
Upvotes: 1
Reputation: 2597
Like Akina says, I can use Generated Columns. https://dev.mysql.com/doc/refman/8.0/en/create-index.html
Upvotes: 0