Improve count query with join and where statement - mysql

I'm running a count query which is very slow, how can improve this?
I've got the following query, but it takes around 1.33 seconds:
select
count(*) as aggregate
from
`tickets`
inner join `orders` on `orders`.`id` = `tickets`.`order_id`
where
`orders`.`status` = 'paid' and
`tickets`.`created_at` > '2023-01-01 00:00:00'
The tickets table has around 650000 rows and the order table has around 320000 rows.
This is the result of SHOW CREATE TABLE tickets:
CREATE TABLE `tickets` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`tickettype_id` int unsigned NOT NULL,
`order_id` int unsigned NOT NULL,
`variant_id` bigint unsigned DEFAULT NULL,
`seat_id` bigint unsigned DEFAULT NULL,
`barcode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`first_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`last_name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`telephone` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`birthday` date DEFAULT NULL,
`age` int unsigned DEFAULT NULL,
`gender` enum('m','f') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`price` double(10,2) DEFAULT NULL,
`extra_info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `tickets_barcode_unique` (`barcode`),
KEY `tickets_tickettype_id_foreign` (`tickettype_id`),
KEY `tickets_order_id_foreign` (`order_id`),
KEY `tickets_order_id_index` (`order_id`),
KEY `tickets_tickettype_id_index` (`tickettype_id`),
KEY `tickets_seat_id_foreign` (`seat_id`),
KEY `tickets_variant_id_foreign` (`variant_id`),
CONSTRAINT `tickets_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
CONSTRAINT `tickets_seat_id_foreign` FOREIGN KEY (`seat_id`) REFERENCES `seatplan_seats` (`id`) ON DELETE SET NULL,
CONSTRAINT `tickets_tickettype_id_foreign` FOREIGN KEY (`tickettype_id`) REFERENCES `tickets_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `tickets_variant_id_foreign` FOREIGN KEY (`variant_id`) REFERENCES `ticket_variants` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=2945088 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
How can I improve the speed?

The performance of your query depends on several factors. Such as,
The table size
Performance of your machine
Indexing etc.
If you dont have indices created for status, order_id and created_at, better create them. Which can significantly improve the query performance.
CREATE INDEX order_id_index ON tickets(order_id);
CREATE INDEX status_index ON orders(status);
CREATE INDEX created_at_index ON tickets(created_at);
Additionally, if you are using PostgreSQL, try running VACUUM on your tables which removes the dead tuples and improves performance.

First of all
You need to add two indexes :
CREATE INDEX order_id_idx ON tickets(order_id);
// composite index since you are using both columns in where
CREATE INDEX status_created_at_idx ON tickets(status, created_at);
The query optimizer uses the composite indexes for queries that test all columns in the index, or queries that test the first columns, the first two columns, and so on.
More informations regarding composite can be found here

Related

Getting cannot find an index in the referenced table error

Cannot find an index in the referenced table where the referenced columns appear as the first columns, or column types in the table and the referenced table do not match for constraint. Note that the internal storage type of ENUM and SET changed in tables created with >= InnoDB-4.1.12, and such columns in old tables cannot be referenced by such columns in new tables.
Above is the full description of error im getting. i checked the indexes of both table and should be fine but it still gives me this error.
Below is the tables structure.
CREATE TABLE `contact_address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`address_type` int(5) DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`postcode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`area` int(5) DEFAULT NULL,
`state` int(5) DEFAULT NULL,
`country` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`fax` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`contact_branch_id` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(4) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`updated_by` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_c_a_area` (`area`),
KEY `fk_c_a_state` (`state`),
KEY `fk_c_a_country` (`country`),
KEY `fk_c_a_contact_branch_id` (`contact_branch_id`),
KEY `fk_c_a_created_by` (`created_by`),
CONSTRAINT `fk_c_a_area` FOREIGN KEY (`area`) REFERENCES `ref_area` (`area_id`),
CONSTRAINT `fk_c_a_contact_branch_id` FOREIGN KEY (`contact_branch_id`) REFERENCES `contact_branch` (`id`),
CONSTRAINT `fk_c_a_created_by` FOREIGN KEY (`created_by`) REFERENCES `user` (`id`),
CONSTRAINT `fk_c_a_state` FOREIGN KEY (`state`) REFERENCES `ref_state` (`state_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `ref_countries` (
`country_code` char(2) NOT NULL,
`country_id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(80) NOT NULL,
`alpha_3` char(3) DEFAULT NULL,
`calling_code` int(5) NOT NULL,
`continent_name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`country_code`),
KEY `country_id` (`country_id`)
) ENGINE=InnoDB AUTO_INCREMENT=253 DEFAULT CHARSET=utf8mb4;
Im trying to run this and giving me the error.
ALTER TABLE `contact_address`
ADD CONSTRAINT `fk_c_a_countries` FOREIGN KEY (`country`)
REFERENCES `ref_countries` (`country_code`);
The error message you're getting suggests that there's a problem with the foreign key constraint that you're trying to add to the contact_address table. Based on the table definitions you've provided, there are a couple of things that could be causing the issue:
The data type of the country column in the contact_address table is char(2), while the data type of the country_code column in the ref_countries table is char(2) NOT NULL. The NOT NULL constraint on the country_code column may be causing the problem.
Another possibility is that the ref_countries table have not have AUTO_INCREMENT on country_code column, but the contact_address table's country column is referencing that.
You can try the following:
Remove the NOT NULL constraint from the country_code column in the ref_countries table.
Add AUTO_INCREMENT to the country_code column in the ref_countries table.
Also, make sure that there is a matching value in the ref_countries table for each value of the country column in the contact_address table.

MySQL Performance issue: select query takes forever

This is vitally important query of the project that calculates statistic information for each user, generates almost 300k rows but it takes forever to get answer.
The problem is, this query is needed to be executed almost every 20-30 seconds and the row count always grows.
Despite the fact that the fields that used in join and where are indexed it takes around 2000 seconds to get the answer from query.
One another fact is, the tables used in this query are large. For example, IconKeyword holds almost 95M records.
Please take a look and tell me how can I optimize this query
SELECT
Icon.`user_id` AS user_id,
Keyword.`id` AS keyword_id,
Keyword.`title` AS keyword_title,
Keyword.`demand` AS keyword_demand,
count( IconKeyword.`iconID` ) AS ico_count,
Icon.`type` AS icon_type,
Keyword.`common` AS common
FROM
Icon
INNER JOIN IconKeyword ON IconKeyword.iconID = Icon.id
INNER JOIN Keyword ON Keyword.id = IconKeyword.keywordID
WHERE
Keyword.is_deleted = 0
AND
Keyword.restricted = 0
GROUP BY
Icon.`user_id`,
Icon.type,
Keyword.id;
And here is explain results:
Create tables:
CREATE TABLE `Icon` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`description` text CHARACTER SET utf8 COLLATE utf8_general_ci,
`type` tinyint DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`user_id` int unsigned DEFAULT NULL,
`f_id` int unsigned DEFAULT NULL,
`color` tinyint unsigned DEFAULT '0',
`pack_id` int unsigned DEFAULT NULL,
`pack_bg` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`fi_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`is_deleted` tinyint unsigned DEFAULT '0',
`count_of_sets` int unsigned NOT NULL DEFAULT '0',
`p_hash` binary(64) DEFAULT NULL,
`hash_bit_count` int unsigned GENERATED ALWAYS AS (bit_count(`p_hash`)) STORED,
`checked` tinyint unsigned DEFAULT '0',
`md5` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `f_id` (`f_id`) USING BTREE,
KEY `user_id` (`user_id`) USING BTREE,
KEY `id` (`id`,`type`,`user_id`) USING BTREE,
KEY `type` (`type`) USING BTREE,
KEY `uri` (`uri`) USING BTREE,
KEY `hash_bit_count` (`hash_bit_count`) USING BTREE,
KEY `is_deleted` (`is_deleted`),
KEY `checked` (`checked`),
KEY `user_id_2` (`user_id`,`type`) USING BTREE,
CONSTRAINT `Icon_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=118691 DEFAULT CHARSET=utf8
CREATE TABLE `Keyword` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`slug` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`common` tinyint unsigned DEFAULT '0',
`demand` int DEFAULT '0',
`f_id` int unsigned DEFAULT NULL,
`is_deleted` tinyint unsigned DEFAULT '0',
`needs_review` tinyint unsigned DEFAULT '0',
`checked` tinyint unsigned DEFAULT '0',
`restricted` tinyint unsigned DEFAULT '0',
`word_checked` tinyint unsigned DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `slug` (`slug`) USING BTREE,
KEY `title` (`title`) USING BTREE,
KEY `is_deleted` (`is_deleted`) USING BTREE,
KEY `restricted` (`restricted`) USING BTREE,
KEY `restricted_2` (`restricted`,`is_deleted`,`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30000392 DEFAULT CHARSET=utf8
CREATE TABLE `IconKeyword` (
`iconID` int unsigned NOT NULL,
`keywordID` int unsigned NOT NULL,
PRIMARY KEY (`iconID`,`keywordID`) USING BTREE,
UNIQUE KEY `keywordID_2` (`keywordID`,`iconID`),
KEY `keywordID` (`keywordID`) USING BTREE,
KEY `iconID` (`iconID`) USING BTREE,
CONSTRAINT `ik_ibfk_1` FOREIGN KEY (`keywordID`) REFERENCES `Keyword` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `ik_ibfk_2` FOREIGN KEY (`iconID`) REFERENCES `Icon` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
For your query, you can try adding indexes on:
keyword(is_deleted, is_restricted, id)
IconKeyword(KeywordId, IconId)
Icon(id) (which should already exist because id is a primary key)
The query will still need to do a lot of work for the aggregation, but this might help.
I guess the number of records that have Keyword.is_deleted = 0 AND Keyword.restricted = 0 is quite large, so adding indexes here wouldn't help much.
What you can try is helping the aggregation works faster by adding a Multiple-Column Indexes, specifically (Icon.user_id, Icon.type) because it's what you're using in GROUP BY
Also, can you provide an EXPLAIN result of this query so we can better understand what is causing the performance problem.

Error while I'm trying to partitioning a table

Here is my posts table:
CREATE TABLE `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`img` varchar(255) COLLATE utf8_croatian_ci NOT NULL,
`vid` varchar(255) COLLATE utf8_croatian_ci NOT NULL,
`title` varchar(255) COLLATE utf8_croatian_ci NOT NULL,
`subtitle` varchar(255) COLLATE utf8_croatian_ci NOT NULL,
`auth` varchar(54) COLLATE utf8_croatian_ci NOT NULL,
`story` longtext COLLATE utf8_croatian_ci NOT NULL,
`tags` varchar(255) COLLATE utf8_croatian_ci NOT NULL,
`status` varchar(100) COLLATE utf8_croatian_ci NOT NULL,
`moder` varchar(50) COLLATE utf8_croatian_ci NOT NULL,
`rec` varchar(50) COLLATE utf8_croatian_ci NOT NULL,
`pos` varchar(50) COLLATE utf8_croatian_ci NOT NULL,
`inde` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=117 DEFAULT CHARSET=utf8 COLLATE=utf8_croatian_ci
I want to make two partitions in order to improve query performances.
First partition should contain all non-archive rows.
Second partition - all archive rows.
ALTER TABLE posts
PARTITION BY LIST COLUMNS (status)
(
PARTITION P1 VALUES IN ('admin', 'moder', 'public', 'rec'),
PARTITION P2 VALUES IN ('archive')
);
phpmyadmin error:
Static analysis:
1 errors were found during analysis.
Unrecognized alter operation. (near "" at position 0)
MySQL said:
#1503 - A PRIMARY KEY must include all columns in the table's partitioning function
Any help?
What queries are you trying to speed up? Since the only index you currently have, WHERE id=... or WHERE id BETWEEN ... AND ... are the only queries that will be fast. And the partitioning you suggest will not help much for other queries.
You seem to have only dozens of rows; don't consider partitioning unless you expect to have at least a million rows.
status has only 5 values? Then make it ENUM('archive', 'admin', 'moder', 'public', 'rec') NOT NULL. That will take 1 byte instead of lots.
If you will be querying on date and/or status and/or auth, then let's talk about indexes, especially 'composite' indexes on such. And, to achieve the "archive" split you envision, put status as the first column in the index.

Index not being used for sort in joined view

I have the following schema:
CREATE TABLE `news` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`news_category_id` int(10) unsigned NOT NULL,
`news_type_id` int(10) unsigned NOT NULL,
`news_pictures_main_id` int(10) unsigned DEFAULT NULL,
`title` tinytext COLLATE latin1_general_ci,
`body` text COLLATE latin1_general_ci,
`tmstp` timestamp NULL DEFAULT NULL,
`subcategory` varchar(64) COLLATE latin1_general_ci DEFAULT NULL,
`source` varchar(128) COLLATE latin1_general_ci DEFAULT NULL,
`old_id` int(10) unsigned DEFAULT NULL,
`tags` text COLLATE latin1_general_ci,
PRIMARY KEY (`id`),
KEY `news_time_idx` (`tmstp`),
KEY `fk_news_news_pictures1` (`news_pictures_main_id`),
KEY `fk_news_news_category1` (`news_category_id`),
KEY `fk_news_news_type1` (`news_type_id`),
CONSTRAINT `fk_news_news_category1` FOREIGN KEY (`news_category_id`) REFERENCES `news_category` (`id`) ON UPDATE CASCADE,
CONSTRAINT `fk_news_news_pictures1` FOREIGN KEY (`news_pictures_main_id`) REFERENCES `news_pictures` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_news_news_type1` FOREIGN KEY (`news_type_id`) REFERENCES `news_type` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB
CREATE TABLE `news_pictures` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`path` text COLLATE latin1_general_ci,
`description` text COLLATE latin1_general_ci,
`author` varchar(45) COLLATE latin1_general_ci DEFAULT NULL,
`news_id` int(10) unsigned DEFAULT NULL,
`temp_id` varchar(40) COLLATE latin1_general_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `filename_old_id_unq` (`path`(20),`temp_id`(6)),
KEY `fk_news_pictures_news1` (`news_id`),
KEY `temp_id_idx` (`temp_id`(8)),
CONSTRAINT `fk_news_pictures_news1` FOREIGN KEY (`news_id`) REFERENCES `news` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
CREATE TABLE `news_category` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) COLLATE latin1_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
CREATE TABLE `news_type` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) COLLATE latin1_general_ci DEFAULT NULL,
`slug` varchar(45) COLLATE latin1_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
KEY `news_type_slug_idx` (`slug`)
) ENGINE=InnoDB
From that, there is derived the following view:
CREATE OR REPLACE VIEW `news_full` AS select `n`.`id` AS `id`,
`n`.`title` AS `title`,
`n`.`body` AS `body`,
`n`.`tmstp` AS `tmstp`,
`n`.`subcategory` AS `subcategory`,
`n`.`source` AS `source`,
`n`.`old_id` AS `old_id`,
`n`.`news_type_id` AS `news_type_id`,
`n`.`tags` AS `tags`,
`nt`.`name` AS `news_type_name`,
`nt`.`slug` AS `news_type_slug`,
`n`.`news_pictures_main_id` AS `news_pictures_main_id`,
`np`.`path` AS `news_pictures_main_path`,
`np`.`description` AS `news_pictures_main_description`,
`np`.`author` AS `news_pictures_main_author`,
`np`.`temp_id` AS `news_pictures_main_temp_id`,
`n`.`news_category_id` AS `news_category_id`,
`nc`.`name` AS `news_category_name`
from (((`news` `n`
left join `news_pictures` `np` on((`n`.`news_pictures_main_id` = `np`.`id`)))
join `news_category` `nc` on((`n`.`news_category_id` = `nc`.`id`)))
join `news_type` `nt` on((`n`.`news_type_id` = `nt`.`id`)));
However, if I try to run the following query:
select * from news_full order by tmstp limit 100
I get the following execution plan (please click on the image to expand it):
Notice the Using temporary; Using filesort field in the first step. But this is weird, because tmstp field is indexed on the base table.
First I thought this was due the left join on the view, but I've changed it to inner join and I got the same results.
Edit
As #Michael-sqlbot cleverly noticed, the query optimizer is inverting the order of the base tables, putting news_category (nc) first.
If I change the query that creates the view to use only LEFT JOINs it seems to work:
The execution times, as expected, as blatantly different:
Not satisfied, I created another view with the original query, adding the STRAIGHT_JOIN statement. So, the query plan comes as follows:
So, it's not using the index.
However, if I run the plan for the base query adding the same ORDER BY and LIMIT clauses, it does uses the index:
(Not an answer, but some other issues to bring up...)
UNIQUE KEY `filename_old_id_unq` (`path`(20),`temp_id`(6))
That constrains the first 20 characters of path, together with the first 6 characters of temp_id to be unique across the table. Did you really want that?
I suspect the optimizer will never use both columns of that index. (In general, prefixing is useless.)
And...
`title` tinytext COLLATE latin1_general_ci
Change to VARCHAR(255). There are disadvantages of TINYTEXT and perhaps no advantages.

Comparing MySQL and SQLite create table statements

So I am trying to make an app with "code first" approach and active record ORM. I am willing to work with MySQL and SQLite (both) in this app. Here is how I am creating a database:
(this is a mockup table I came up with solely for this question)
$this->int("id", self::INT_MEDIUM)->unSigned()->primaryKey()->autoIncrement();
$this->string("hash", 64, self::STR_FIXED)->unique();
$this->enum("status", "available","sold","pending")->defaultValue("available");
$this->int("category", self::INT_MEDIUM)->unSigned()->defaultValue(0);
$this->string("name")->unique();
$this->text("descr")->nullable();
$this->decimal("price", 10, 4)->defaultValue(1.234);
$this->uniqueKey("store_np", "name", "price");
$this->foreignKey("category", "categories", "id");
and then my code generates CREATE TABLE statement for me, here are the results:
MySQL:
CREATE TABLE `products` (
`id` mediumint UNSIGNED PRIMARY KEY auto_increment NOT NULL,
`hash` char(64) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`status` enum('available','sold','pending') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL default 'available',
`category` mediumint UNSIGNED NOT NULL default 0,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`descr` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci default NULL,
`price` decimal(10,4) NOT NULL default 1.234,
UNIQUE KEY (`hash`),
UNIQUE KEY (`name`),
UNIQUE KEY `store_np` (`name`,`price`),
FOREIGN KEY (`category`) REFERENCES `categories`(`id`)
) ENGINE=InnoDB;
SQLite:
CREATE TABLE `products` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`hash` TEXT UNIQUE NOT NULL,
`status` TEXT CHECK(status in ('available','sold','pending') ) NOT NULL default 'available',
`category` INTEGER UNSIGNED NOT NULL default 0,
`name` TEXT UNIQUE NOT NULL,
`descr` TEXT default NULL,
`price` REAL NOT NULL default 1.234,
CONSTRAINT `store_np` UNIQUE (`name`,`price`),
CONSTRAINT `cnstrnt_category_frgn` FOREIGN KEY (`category`) REFERENCES `categories`(`id`)
);
I executed both queries in phpMyAdmin and phpLiteAdmin, and both seemed to worked fine.
Here are my concerns:
For example, I didn't know I cannot use "UNSIGNED" with "PRIMARY KEY AUTOINCREMENT" in SQLite, which gave me hard time to figure out. Is there anything else like that I should be concerned about?
Even though both statements were executed successfully, are they going to work as expected? Especially the constraints in SQLite
Please check "status" column in SQLite, is it appropriate method to use as an alternative to MySQL's enum?