ypercube đã giải quyết vấn đề. Các truy vấn con là hoàn toàn không cần thiết, và toàn bộ hoạt động với các phép nối đơn giản. Tuy nhiên, điều kỳ lạ là trình tối ưu hóa của MySQL không thể sử dụng truy vấn ban đầu của tôi. Xem dưới đây cho câu hỏi và rất nhiều chi tiết. Cộng với một giải pháp hoàn chỉnh ở cuối câu hỏi của tôi. Nó dựa trên câu trả lời của ypercube.
Mỗi truy vấn con rất nhanh, dưới 1 giây. Các truy vấn con 5-6 được tham gia (một số LEFT
, một số INNER
) và thời gian nấm đến 400 giây.
Truy vấn tổng thể tôi đang sử dụng để kiểm tra chỉ trả về 441 hàng.
Tôi đã thử đặt từng truy vấn con trong truy vấn "TẠO BẢNG". Mỗi cái được thực hiện trong vòng dưới 1 giây. Sau đó, tôi làm lại truy vấn bên ngoài bằng cách sử dụng các bảng mới được tạo và nó cũng chạy trong chưa đầy 1 giây. Vì vậy, không có vấn đề thực sự với các liên kết. Tôi đặt các chỉ mục id
cho các bảng đã tạo của tôi. Tất cả các bảng được nối trên khớp id
= id
.
Làm cách nào để MySQL thực hiện truy vấn hiệu quả? Tôi phải sử dụng bảng tạm thời? Tôi đã viết một loạt các mã PHP để kết hợp nhiều tham gia truy vấn con, vì vậy tôi chỉ muốn tìm ra cách làm cho nó hoạt động, nếu có thể.
Tôi đã thử sử dụng từ khóa "STRAIGHT_JOIN" và loại bỏ từ bên ngoài ORDER BY
. Điều đó đã giảm thời gian truy vấn xuống còn 90 giây. Nhưng tôi sẽ nhận được tối đa 1 giây.
Tôi đã thử STRAIGHT_JOIN
với ORDER BY
và mất 235 giây. Vì vậy, có vẻ như bên ngoài ORDER BY
là một vấn đề hiệu suất lớn.
BIÊN TẬP:
Đã thử nghiệm bằng cách sử dụng các bảng tạm thời. Truy vấn chạy rất nhanh. Nhưng phải có một cách để làm cho mysql làm điều đó nhanh chóng với THAM GIA.
Ngoài ra, nhật ký truy vấn chậm hiển thị:
Rows_examined: 484006914
484 triệu hàng trông giống như một sản phẩm cartesian. Tại sao nó kiểm tra rất nhiều hàng?
Truy vấn có cấu trúc này:
SELECT t0.`id`, t1.`length`, t2.`height`, t3.`family`
FROM
`products` t0
INNER JOIN
(
SELECT t1.`id`, t2.`value` AS `length`
FROM `products` t1
INNER JOIN `product_eav_decimal` t2
ON t1.`id` = t2.`product_id`
WHERE t2.`attribute_id` = 91
AND t2.`value` BETWEEN 15 AND 35
) t1
ON t0.`id` = t1.`id`
LEFT JOIN
(
SELECT t1.`id`, t2.`value` AS `height`
FROM `products` t1
INNER JOIN `product_eav_decimal` t2
ON t1.`id` = t2.`product_id`
WHERE t2.`attribute_id` = 80
# no other conditions
) t2
ON t0.`id` = t2.`id`
INNER JOIN
(
.
.
.
) t6
ON t0.`id` = t6.`id`
ORDER BY t0.`id` ASC
... vv LEFT THAM GIA được sử dụng khi không có điều kiện nào khác trong truy vấn con ngoài thuộc tính_id. INNER THAM GIA sử dụng khi có một số điều kiện khác. Điều này tạo ra một kết quả tìm kiếm hợp lệ. Truy vấn hoạt động, chỉ mất 400 giây thay vì 0,04.
Nếu không ai biết cách làm cho cú pháp THAM GIA hoạt động, thì tôi sẽ sử dụng các bảng tạm thời vì nó dường như hoạt động.
NHỮNG CÁI BÀN:
1.) sản phẩm
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sku` varchar(127) NOT NULL COMMENT '3char vencode + model',
`model` varchar(127) NOT NULL,
`vendor_id` int(11) DEFAULT NULL,
`updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `sku` (`sku`),
KEY `model` (`model`),
KEY `vendor_id` (`vendor_id`),
CONSTRAINT `FK1` FOREIGN KEY (`vendor_id`) REFERENCES `vendors` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=153282 DEFAULT CHARSET=utf8
2.) số thập phân
CREATE TABLE `product_eav_decimal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`attribute_id` int(11) DEFAULT NULL,
`value` decimal(11,3) DEFAULT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `natural_key` (`product_id`,`attribute_id`,`value`),
UNIQUE KEY `product_id_2` (`product_id`,`attribute_id`),
KEY `last_update` (`last_update`),
KEY `product_id` (`product_id`),
KEY `attribute_id` (`attribute_id`),
KEY `value` (`value`),
CONSTRAINT `FK1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK2` FOREIGN KEY (`attribute_id`) REFERENCES `attributes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=370772 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
3.) varchar (tham chiếu một bảng khác, values_varchar
bảng cho các giá trị varchar thực tế)
CREATE TABLE `product_eav_varchar` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`attribute_id` int(11) DEFAULT NULL,
`value_id` int(11) DEFAULT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `natural_key` (`product_id`,`attribute_id`,`value_id`),
KEY `last_update` (`last_update`),
KEY `product_id` (`product_id`),
KEY `value_id` (`value_id`),
KEY `attribute_id` (`attribute_id`),
CONSTRAINT `FK1` FOREIGN KEY (`value_id`) REFERENCES `values_varchar` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK2` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK3` FOREIGN KEY (`attribute_id`) REFERENCES `attributes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=86049 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Chuyển thể từ câu trả lời của ypercube:
SELECT t0.id,
t1.`value` AS length,
t2.`value` AS height,
t3.`value` AS family,
t5.`value` AS type
FROM
products t0
INNER JOIN # INNER used when search criteria
# length (only searched values)
product_eav_decimal t1
ON t1.product_id = t0.id
AND t1.attribute_id = 91
AND t1.`value` BETWEEN 15 AND 35 # search criteria
LEFT JOIN # LEFT used when no search criteria
# height (all, including blank/null)
product_eav_decimal t2
ON t2.product_id = t0.id
AND t2.attribute_id = 80
LEFT JOIN # LEFT - no search critera
# family - varchar type requires extra join to values table
product_eav_varchar t3
ON t3.product_id = t0.id
AND t3.attribute_id = 77
LEFT JOIN # LEFT join to values table matches eav table join
values_varchar t4
ON t3.value_id = t4.id
# search criteria would be here. see next
INNER JOIN # INNER - search criteria below
# type - varchar requires extra join, see below
product_eav_varchar t5
ON t5.product_id = t0.id
AND t5.attribute_id = 76
INNER JOIN # INNER join to values table matches eav table join
values_varchar t6
ON t5.value_id = t6.id
# search criteria
AND (t6.value LIKE "%sofa%" COLLATE utf8_general_ci OR t6.value LIKE "%chair%" COLLATE utf8_general_ci)
ORDER BY t0.id ASC;
Các truy vấn hoạt động. Nó chạy trong vài mili giây. Nếu các thuật ngữ tìm kiếm hoặc giới hạn phạm vi được đưa ra, nó sẽ trả về kết quả CHỈ phù hợp, sử dụng INNER THAM GIA. Trong trường hợp không có tiêu chí, nó sử dụng TRÁI PHIẾU để trả về bất kỳ giá trị nào (bao gồm NULL / để trống).
Cập nhật tháng 8 năm 2014 - hiện có 400-500 nghìn hàng trong products
bảng và kiểu truy vấn được sử dụng ở trên vẫn chạy rất nhanh. Có vẻ như việc tham gia nhanh hơn nhiều so với các truy vấn con trong MySQL.
SHOW CREATE TABLE
đầu ra) cho 2 bảng.