Bob*_*odo 5 mysql performance order-by subquery mysql-5.6 query-performance
我尝试将 3 个表(产品、价格、类别)连接在一起,以从连接的表中获取最新和最低价格的结果。
我能够在 MySQL 5.5 上获得预期结果,但升级到 5.6 后,ORDER BY
子查询似乎被忽略了。如何更改查询以使其工作ORDER BY
?
该查询应该是:
3张表的关系如下:
表信息:
mysql> show columns from products;
+----------------+------------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(300) | NO | MUL | NULL | |
| active | tinyint(1) | YES | | 1 | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| matchkey | varchar(300) | NO | MUL | NULL | |
| sku | varchar(50) | YES | MUL | NULL | |
+----------------+------------------+------+-----+---------------------+-----------------------------+
mysql> show columns from prices;
+---------------+---------------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------------+------+-----+---------------------+-----------------------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| price_selling | decimal(8,2) | NO | MUL | NULL | |
| price_before | decimal(8,2) | NO | | 0.00 | |
| product_id | int(10) unsigned | NO | MUL | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+---------------+---------------------+------+-----+---------------------+-----------------------------+
mysql> show columns from categories;
+------------------+------------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| parent_id | int(11) | YES | MUL | NULL | |
| lft | int(11) | YES | MUL | NULL | |
| rgt | int(11) | YES | MUL | NULL | |
| depth | int(11) | YES | | NULL | |
| name | varchar(255) | NO | MUL | NULL | |
| active | tinyint(1) | YES | | 1 | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+------------------+------------------+------+-----+---------------------+-----------------------------+
mysql> show columns from category_product;
+--------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------+-------+
| product_id | int(10) unsigned | NO | PRI | NULL | |
| category_id | int(10) unsigned | NO | PRI | NULL | |
+--------------------+------------------+------+-----+---------+-------+
Run Code Online (Sandbox Code Playgroud)
在 MySQL 5.5 上运行的查询是:
SELECT
p3.pid AS id, category_product.product_id, p3.name, p3.priceId,
p3.product_id, p3.price_selling, p3.price_before, MIN(p3.price_selling) AS minprice,
p3.matchkey, categories.url_key AS category_urlkey
FROM category_product
RIGHT JOIN (
SELECT
pp.priceId, pp.product_id, pp.price_selling, pp.price_before,
pp.pid, pp.name, pp.matchkey
FROM (
SELECT
prices.id AS priceId, prices.product_id, prices.price_selling, prices.price_before,
products.id AS pid, products.name, products.matchkey
FROM prices
RIGHT JOIN products ON prices.product_id = products.id
WHERE prices.id = (SELECT MAX(p.id) FROM prices p WHERE p.product_id = prices.product_id)
) AS pp
GROUP BY pp.pid
ORDER BY pp.price_selling ASC
) AS p3 ON category_product.product_id = p3.pid
RIGHT JOIN categories ON categories.id = category_product.category_id AND categories.id = 488
GROUP BY p3.matchkey
ORDER BY p3.pid DESC;
Run Code Online (Sandbox Code Playgroud)
表结构和示例数据可用于测试:
--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
`active` tinyint(1) DEFAULT '1',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`matchkey` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
`sku` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `products_sku_index` (`sku`),
KEY `id` (`id`),
KEY `matchkey` (`matchkey`),
FULLTEXT KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=60057 ;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `name`, `active`, `created_at`, `updated_at`, `matchkey`, `sku`) VALUES
(26195, 'Samsung Galaxy S3 Mini GT-I8200 Unlocked Cellphone, White, 8GB', 1, '2016-01-23 14:38:25', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(26425, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:28', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(26632, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:29', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(28212, 'Samsung Galaxy S3 Mini GT-I8200 Unlocked Cellphone, White, 8GB', 1, '2016-01-23 14:38:51', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(35111, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:39:03', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(37611, '[From U.S.A]Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:39:29', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(60017, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:11', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL);
--
-- Table structure for table `prices`
--
CREATE TABLE IF NOT EXISTS `prices` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`price_selling` decimal(8,2) NOT NULL,
`price_before` decimal(8,2) NOT NULL DEFAULT '0.00',
`product_id` int(10) unsigned NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `price_selling` (`price_selling`),
KEY `id` (`id`),
KEY `product_id` (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=114663 ;
--
-- Dumping data for table `prices`
--
INSERT INTO `prices` (`id`, `price_selling`, `price_before`, `product_id`, `created_at`, `updated_at`) VALUES
(33585, '1052.40', '0.00', 26195, '2016-01-22 09:53:02', '0000-00-00 00:00:00'),
(65594, '1052.40', '0.00', 26195, '2016-01-23 01:27:08', '0000-00-00 00:00:00'),
(110038, '1052.40', '0.00', 26195, '2016-01-23 14:38:25', '0000-00-00 00:00:00'),
(33815, '1052.40', '0.00', 26425, '2016-01-22 09:55:17', '0000-00-00 00:00:00'),
(65790, '1052.40', '0.00', 26425, '2016-01-23 01:27:11', '0000-00-00 00:00:00'),
(110209, '1016.40', '0.00', 26425, '2016-01-23 14:38:28', '0000-00-00 00:00:00'),
(34022, '1052.40', '0.00', 26632, '2016-01-22 09:57:43', '0000-00-00 00:00:00'),
(66020, '1052.40', '0.00', 26632, '2016-01-23 01:27:13', '0000-00-00 00:00:00'),
(110373, '1052.40', '0.00', 26632, '2016-01-23 14:38:29', '0000-00-00 00:00:00'),
(35602, '960.25', '0.00', 28212, '2016-01-22 10:12:50', '0000-00-00 00:00:00'),
(67396, '960.25', '0.00', 28212, '2016-01-23 01:27:45', '0000-00-00 00:00:00'),
(111555, '960.25', '0.00', 28212, '2016-01-23 14:38:51', '0000-00-00 00:00:00'),
(71346, '929.20', '0.00', 35111, '2016-01-23 01:37:05', '0000-00-00 00:00:00'),
(112318, '899.30', '0.00', 35111, '2016-01-23 14:39:03', '0000-00-00 00:00:00'),
(73852, '936.10', '0.00', 37611, '2016-01-23 01:54:47', '0000-00-00 00:00:00'),
(113711, '936.10', '0.00', 37611, '2016-01-23 14:39:29', '0000-00-00 00:00:00'),
(109601, '1108.99', '2369.91', 60017, '2016-01-23 14:38:08', '0000-00-00 00:00:00');
--
-- Table structure for table `categories`
--
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`lft` int(11) DEFAULT NULL,
`rgt` int(11) DEFAULT NULL,
`depth` int(11) DEFAULT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`url_key` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
`active` tinyint(1) DEFAULT '1',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `categories_parent_id_index` (`parent_id`),
KEY `categories_lft_index` (`lft`),
KEY `categories_rgt_index` (`rgt`),
KEY `url_key` (`url_key`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=825 ;
--
-- Dumping data for table `categories`
--
INSERT INTO `categories` (`id`, `parent_id`, `lft`, `rgt`, `depth`, `name`, `active`, `url_key`, `created_at`, `updated_at`) VALUES
(1, NULL, 1, 968, 0, 'Root', 1, NULL, '2016-01-23 13:19:51', '2016-01-23 13:19:51'),
(487, 1, 446, 453, 1, 'Mobile & Communication', 1, 'mobile-communication', '2016-01-23 13:19:51', '2016-01-23 13:19:51'),
(488, 487, 447, 448, 2, 'Mobile Phones', 1, 'mobile-phones', '2016-01-25 06:27:37', '2016-01-25 06:27:37');
--
-- Table structure for table `category_product`
--
CREATE TABLE IF NOT EXISTS `category_product` (
`product_id` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`product_id`,`category_id`),
KEY `product_id` (`product_id`),
KEY `category_id` (`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Dumping data for table `category_product`
--
INSERT INTO `category_product` (`product_id`, `category_id`) VALUES
(26195, 1),
(26195, 487),
(26195, 488),
(26425, 1),
(26425, 487),
(26425, 488),
(26632, 1),
(26632, 487),
(26632, 488),
(28212, 1),
(28212, 487),
(28212, 488),
(35111, 1),
(35111, 487),
(35111, 488),
(37611, 1),
(37611, 487),
(37611, 488),
(60017, 1),
(60017, 487),
(60017, 488);
Run Code Online (Sandbox Code Playgroud)
如果无法解决问题,降级到 5.5 是我最后的选择。我想重写查询,我尝试更改查询仍然没有幸运地让它工作。我认为我编写的查询有问题。
对于上面提供的测试数据,查询应返回(类别 ID:488)下的产品。该查询用于价格比较网站。当用户点击网站上的类别(“手机”-数据库中的类别ID-“类别”表为488)链接时,网站将列出所有产品(按“matchkey”列分组),显示该产品的最低价格该产品组。
添加WHERE categories.id = 488
或categories.name = 'Mobile Phones'
,我仍然得到相同的结果。问题是查询结果没有显示最低价格,即使我ORDER BY pp.price_selling ASC
在子查询上写入。
演示:
上面的两个演示都使用相同的查询,但结果不同。
SELECT a, b ...
GROUP BY a
Run Code Online (Sandbox Code Playgroud)
是自找麻烦。您可能在 5.5 中“幸运”,在 5.6 中“不幸”。
问题是每个“组”都可以显示的任何值。b
当然,在某些情况下,给定的值a
唯一地映射到给定的值b
(例如,在标准化表中),但感觉与这里的情况不同。可以看到有问题:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
Run Code Online (Sandbox Code Playgroud)
在执行 SELECT 之前。
另请参阅: http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_only_full_group_by
你真的应该切换到 InnoDB。
当您到达 5.7 时,该设置将被默认启用。
归档时间: |
|
查看次数: |
2543 次 |
最近记录: |