10/10/2018, 11:10

Giúp đỡ tối ưu MySQL Query

mình gặp 1 bài toán truy vấn mysql SQL sau:

lấy 3 row kế tiếp trong csdl
vd đánh chỉ số 1 2 3 4 5

chọn 4 thì lấy row 5 1 2
chọn 5 thì 1 2 3
chọn 2 thì 3 4 5

hiện tại mình đã giải quyết dc vấn đề nhưng code dài đến 4 dòng, chứa đến 4 COUNT(*) vậy ae nào gặp phải trường hợp này có cách nào giải tốt hơn mà ko dùng đến PHP thì giúp mình với. xin cám ơn
ngoc_viet08 viết 13:16 ngày 10/10/2018
gọi số chọn là A

1.query 1 : select id from table where id > a order by id asc limit 3

2.count(result) lấy ra số dữ liệu còn thiếu B

3. query 2 : select id from table order by id asc limit B

4. ghép 2 mảng lại.

tối ưu hay ko còn phụ thuộc vào khung cảnh thực tế, tạm thời mình chỉ nghĩ simple là zị.
thuyduongcd viết 13:24 ngày 10/10/2018
Code:
$sql="(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3";
fotech_nd viết 13:25 ngày 10/10/2018
Được gửi bởi diepnghitinh
mình gặp 1 bài toán truy vấn mysql SQL sau:

lấy 3 row kế tiếp trong csdl
vd đánh chỉ số 1 2 3 4 5

chọn 4 thì lấy row 5 1 2
chọn 5 thì 1 2 3
chọn 2 thì 3 4 5

hiện tại mình đã giải quyết dc vấn đề nhưng code dài đến 4 dòng, chứa đến 4 COUNT(*) vậy ae nào gặp phải trường hợp này có cách nào giải tốt hơn mà ko dùng đến PHP thì giúp mình với. xin cám ơn
Thử nghĩ đến việc Union all bảng gốc với n (n=3) phần từ đầu tiên của bảng này xem. SQL server thì mình đã từng làm nhưng MySql mình ko biết nên ko biết viết lệnh cụ thể như thế nào
diepnghitinh viết 13:16 ngày 10/10/2018
Được gửi bởi thuyduongcd
Code:
$sql="(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3";
cám ơn bạn, code của bạn đã giải quyết vấn đề sắp xếp theo ASC
Còn trong vấn đề của mình là DESC và đây là table của mình


item_id item_catid
1-------8
2-------8
3-------8
4-------8
5-------8
7-------10

_ khi mà chọn item_id 4 thì show ra các record có item_id là 3 2 1
_ khi chọn item_id 2 thì show ra các record có item_id là 1 5 4
_ item_id=1 thì show ra các record có item_id là 5 4 3

vậy code sau của mình ko tối ưu chỗ nào vậy các bạn
PHP Code:
$item_id 2;
$item_catid 8;
$limit 3
(SELECT * FROM ((SELECT * FROM shop_product_item ORDER BY item_id DESC) as tb1)
WHERE
item_id < $item_id AND item_catid = $item_catid
ORDER BY item_id DESC)

UNION

(SELECT * FROM ((SELECT * FROM shop_product_item ORDER BY item_id DESC) as tb1)
WHERE
item_catid = $item_catid LIMIT 0,$limit)

LIMIT 0,$limit
VnVision viết 13:21 ngày 10/10/2018
Làm như cách của bạn ngoc_viet08 (tối đa 2 query) là tốt rồi - nếu bạn muốn DESC thì chỉ việc thay ASC bằng DESC và id < X. Nhiều bạn lầm tưởng rằng việc tối ưu hóa query đồng nghĩa với việc giảm số query. Thực tế việc tối ưu hóa bao gồm việc đảm bảo rằng các query của mình sử dụng index khi so sánh hay sort, giảm thiểu số rows mà db sẽ phải scan để trả về kết quả, tránh dùng join query khi mình không hiểu rõ những gì mà nó thực hiện, và cuối cùng mới là giảm số query tới csdl. Những query đơn giản (ko có join) và dựa trên index được thực hiện rất nhanh - và đó chính là lý do mà nhiều website có dữ liệu hàng chục triệu row mà họ vẫn sử dụng mysql một cách hiệu quả, trong khi đó nhiều website chỉ có vài trăm nghìn row nhưng vì dùng những query phức tạp (join, union là nhân tố chính trong những query này) nên performance kém. Nếu muốn đi sâu vào tối ưu hóa mysql thì cái cơ bản nhất bạn phải biết sử dụng là câu lệnh EXPLAIN và hiểu k/q nó trả về.

Được gửi bởi thuyduongcd
Code:
$sql="(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3";
Nếu table có tương đối ít row thì có thể dùng cái này, nhưng khi số row càng nhiều thì performance sẽ càng giảm. Vì vế đầu trong query này sẽ đọc tất cả các row có id > X (X=4 trong trg hợp trên). Nếu table có nhiều row nhưng X là id của một row gần cuối table thì ko sao, vì số row phải đọc cũng ko nhiều. Nhưng nếu X là id của một row ở đầu table thì lại khác. Vừa thử chạy query trên ("(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3") với 1 table > 80.000 row, câu lệnh mất hơn 3 giây để hoàn tất (& trả về 3 row k/q). Trong khi đó tổng thời gian thực hiện 2 câu lệnh sau trên cùng table chỉ mất hơn 1 ms:
1) lấy 3 row có id > X
2) lấy nốt 1 or 2 row ở đầu bản NẾU câu lệnh 1) ko trả về đủ 3 row

Điều quan trọng nhất tôi muốn nói ở đây là khi optimize query bạn phải hiểu rõ cách mà csdl sẽ thực hiện từng câu lệnh của bạn. Thà dùng nhiều câu lệnh đơn giản mà bạn hiểu còn hơn dùng ít câu lệnh mà bạn ko hiểu rõ. Bởi performance của chúng có thể tốt lúc này, nhưng khi db lớn hơn thì performance lại degrade.


Quay lại câu lệnh "(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3" - khi hiểu rõ vấn đề, bạn chỉ cần thêm LIMIT 3 vào vế đầu thì câu lệnh này cũng sẽ đc optimize (chạy hiệu quả & performance ko degrade over time)!
fotech_nd viết 13:19 ngày 10/10/2018
Uh - bổ sung thêm cho các bạn nữa là câu lệnh"(SELECT * FROM table WHERE id>4) UNION (SELECT * FROM table LIMIT 0,3) LIMIT 0,3" sẽ không đúng khi trường ID ko phải là auto increment (tức là cần phải bổ sung order by thì mới đúng)
thuyduongcd viết 13:14 ngày 10/10/2018
Tôi chỉ cho bạn con đường còn đi thế nào là tự bạn. Tôi không đủ thời gian để "ẵm" bạn đến đích rồi thả xuống đúng chỗ cần. Làm như vậy khác nào phế đôi chân của bạn đi.

Tất cả những câu lệnh tôi đưa ra không bao giờ tròn trịa đến mức có thể "plug and play" cả (thậm chí có khi còn sai cả cú pháp). Cho nên việc performance hay optimize gì tôi chả quan tâm, mục đích chính của câu trả lời là hướng người hỏi đến từ khóa UNION. Nếu hiểu ý nghĩa nó rồi thì việc "điều khiển" nó theo ý mình là không có gì khó. Còn nếu cứ bê nguyên xi vào sử dụng mà không hiểu thì thà đừng sử dụng còn hơn.

Và tôi cũng không nghĩ UNION 2 câu query sẽ performance kém hơn việc gọi 2 câu query riêng lẻ. Vấn đề là câu query như thế nào mà thôi.
VnVision viết 13:23 ngày 10/10/2018
Được gửi bởi thuyduongcd
Tất cả những câu lệnh tôi đưa ra không bao giờ tròn trịa đến mức có thể "plug and play" cả (thậm chí có khi còn sai cả cú pháp). Cho nên việc performance hay optimize gì tôi chả quan tâm, mục đích chính của câu trả lời là hướng người hỏi đến từ khóa UNION.
Vấn đề là chủ đề này hỏi về việc làm sao để "tối ưu hoá" 1 nhiệm vụ cụ thể, nên bạn ko thể nói ko quan tâm đến performance hay optimize đc (đó là vấn đề mà chủ thớt đang quan tâm hàng đầu). Và mấu chốt trong việc tối ưu hóa ở đây không phải là việc giảm số lượng query với UNION. Bởi vậy câu trả lời của bạn không hướng người dùng đến đúng điều quan trọng nhất, mà lại đề cao một cái thứ yếu (trong trường hợp cụ thể này).
kenphan19 viết 13:20 ngày 10/10/2018
cũng không hẳn là UNION tốc độ sẽ chậm hơn nếu bảng của bạn có khoảng vài ngàn records thì không si nhê gì cả còn nếu lớn quá lớn thì nên tìm solution khác. Vì cách của NgocViet dù gì cũng 2 lần SELECT.
Bài liên quan
0