[Hỏi] Thứ tự sắp xếp trong kết quả truy vấn MySQL

Discussion in 'Hỏi Đáp Kỹ Thuật' started by money, Oct 12, 2017.

  1. money

    money Hương Chủ

    Table của mình có field ID là PK. Thông thường (thông thường thôi nhé, bỏ qua 1 số trường hợp ngoại lệ) thì khi có 1 truy vấn kiểu như này:
    Code:
    select id, name, content from news where (điều kiện gì đó) LIMIT 50; //Chỉ cần lấy 50 records
    thì MySQL sẽ trả về kết quả theo thứ tự tăng dần của ID.
    Nhưng mình cần nó trả theo thứ tự giảm dần, tức là ID lớn sẽ trả ra trước.
    Nếu mình dùng ORDER BY ID ASC thì đương nhiên là sẽ được nhưng vấn đề nằm ở chỗ: khi ORDER BY ID ASC trên 1 table lớn khoảng vài chục triệu rows thì tốc độ query sẽ chậm đi đáng kể, có khi mất cả chục giây.
    Vậy làm sao để cấu hình mặc định là MySQL sẽ trả ra ID lớn trước các bác nhỉ?
    P/S: có search thử thì thấy 1 số mem trên stackoverflow nói là không có default ORDER SORT trong MySQL nhưng mình thấy hơi vô lý vì tại sao nó luôn sort theo ID nhỏ trước? Chứng tỏ nó vẫn có cơ chế fetch results từ ID nhỏ đến ID lớn đúng không?
     
    Last edited: Oct 12, 2017
  2. Zép Xanh

    Zép Xanh Tân Thủ Thôn

    Anh test thử 2 câu truy vấn ở 2 ORDER nó khác nhau hả anh?

    Nếu anh truyền vào ORDER BY ID DESC thì em nghĩ nó sẽ truy vấn ID từ lớn tới nhỏ, tức ngược lại với ORDER DEFAULT chứ nó đâu có select ra rồi mới fetch result theo ORDER BY. => cũng như nhau vì chỉ khác mỗi tham số chuyền vào ORDER BY.
    đó là em nghĩ!
     
  3. Nai

    Nai MiddleMan Staff Member

    ID khi crawl mình để giá trị âm được không anh, nếu được thì anh để dấu - (âm) trước mỗi giá trị hiện tại. Và những lần sau cũng insert theo giá trị âm xem thế nào.
    Vụ này em ko biết nên đưa ý kiến thế thôi {adore}{adore}{adore} Nếu có ngu cũng cấm cãi với @Nai nhé. Cụ @Sói bảo thế {bann}
     
  4. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    Nếu ID là FK thì nó củng như các cột khác thôi, MySQL không quan tâm về order của chúng lúc SELECT. Order mà bạn nhận được sẻ dựa vào thứ tự INSERT của record => Record nào insert trước thì khi SELECT sẽ được hiện trước.

    Có thể trùng hợp là các record bạn insert sau có ID lớn hơn record trước đó, nên bạn mới có cảm giác là mặc định mysql nó sắp xếp tăng dầng thôi.
     
  5. money

    money Hương Chủ

    Nãy anh copy sang ko để ý :D ORDER BY ASC mới đúng.
     
  6. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    ref: https://dev.mysql.com/doc/refman/5.6/en/limit-optimization.html

    Mình nghĩ @money thuộc case trên. Combine ORDER BY và LIMIT. Không biết bạn có tạo INDEX không, nếu có thì ORDER_BY không thể chậm được.

    Cơ mà túm váy lại là Money nên xài ORDER BY nếu phụ thuộc vào thứ tự kết quả trả về, chứ viết SELECT không không thì không có gì đảm bảo thứ tự tăng / giảm dần cả.
     
  7. money

    money Hương Chủ

    Đúng rồi, vì ID là PK Auto Increment nên cái insert sau sẽ có ID lớn hơn. Nhưng vậy có cách nào để MySQL fetch mặc định lấy cái insert sau ra trước ko bác?
     
  8. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    Theo mình biết là không. Ah mà có một cách, edit source code của mysql đoạn đó rồi compile lại xài {hehe}
     
  9. Zép Xanh

    Zép Xanh Tân Thủ Thôn

    Không liên quan nhưng Cụ @money và cụ @Sói rốt cuộc cụ nào là cụ Andy thế? Làm thiên hạ bấn loạn cả lên {biggrin}
     
  10. Phan Thị

    Phan Thị Bang Chúng

    Chua dc xem cái table nào chục triệu row nên ko biêt khác nhau nhiều ko . vì cơ chế ID lớn hay bé mà được đánh index thì ORDER BY ASC hoac DESC là giống nhau. Tất cả chỉ là cảm giác. Cụ thị dùng EXPLAIN xem câu lệnh ra sao. hoặc CỤ có cái table đó thì tự test rồi so sánh ko thì dùng SELECT LIMIT rồi dùng php sort cái result thôi
     
  11. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    Hình như bạn hiểu sai câu hỏi của @money. Ccần SORT trước rồi mới LIMIT nhé, không phải ngược lại.

    Với lại sorting bằng PHP không phải là ý hay, PHP tuổi gì so với C về tốc độ.
     
    money likes this.
  12. money

    money Hương Chủ

    Không phải khác nhau giữa DESC hay ASC mà khác nhau giữa dùng ORDER BY và không có ORDER BY. Mình test performance rồi mới hỏi chứ.

    Thật ra chi tiết thì nó thế này:

    - Câu query dạng: select ID, name from news where (blah blah ...) có khoảng 1M rows khớp với điều kiện where (điều kiện do user enter vào)
    - Để tối ưu thì mình limit 50 kết quả (chưa dùng ORDER BY gì hết) thì sẽ rất nhanh
    - Nhưng khi mình muốn show ra 50 cái MỚI NHẤT --> phải ORDER BY ID ASC (hoặc 1 field nào đó có INDEX) --> khi đó mới rất chậm

    Bài toán nó là như vậy đó. Mình ngại chuyển sang môi trường khác như ES nên muốn giải quyết trên MySQL cho tiện, nếu ra $ thì sẽ đầu tư thêm :D
     
  13. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    Chậm hơn bao nhiêu % vậy? nếu PK mà có index vẫn chậm hơn rất nhiều khi dùng ORDER BY thì số nhọ rồi, chưa gặp. Cứ test thử giải pháp khác, mất gì đâu.
     
  14. money

    money Hương Chủ

    ý của @Phan Thị là EXPLAIN trên MySQL luôn đó mà. Nhưng cái hiểu lầm ở đây là không phải khác nhau giữa ORDER BY DESC hay ASC mà là có dùng ORDER BY và không dùng ORDER BY.

    Nhân tiên mình explain luôn nè:
    - câu select ID, name where (blah blah ... ) của mình có khoảng 3M rows matched điều kiện
    - sau khi mình thêm order by id desc và xem thời gian thực thi thì total mất 42.30851 giây, riêng thời gian sorting là 42.30784 giây (chiếm 99.99842%)
     
  15. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    OMG, 42s...
    Quá nhiều với 10M+ records, không biết được schema nên chỉ có 1 số lời khuyên:
    - Như đã nói, nhu cầu của bạn bắt buộc phải xài ORDER_BY, đừng tìm mấy cách làm cho mysql sort mặc định như nói ở trên.
    - Xem lại index và composite index cho các cột ở WHERE và ORDER_BY
    - Tối ưu thấp hơn, coi lại data type cho các cột.
    - Không được nữa, thử xài SSD, Memcached, ES?
     
  16. Phan Thị

    Phan Thị Bang Chúng

    chuẩn là CỤ cần đánh index các cột ở chỗ WHERE chung một index , đánh xong là giảm đi khá nhiều đoá
     
  17. money

    money Hương Chủ

    @Luxifer cái kết quả đó là query trên DB có hơn 80M rows, và mình đang dùng SSD Intel rồi, CPU Core i7 16Gb RAM
    Thật ra thì mình đang test trên local nên thử các trường hợp nặng nhất (tức là với điều kiện where mà match nhiều rows nhất). Còn khi deploy site thật thì sẽ limit user lại, bắt nó enter các query dài ra 1 xíu để số matched rows nhỏ lại tầm vài trăm K thì sẽ nhanh hơn nhiều.
    Việc chuyển sang ES thì thật ra lười quá, nên muốn làm trên MySQL cho nhanh, nếu dự án này ra $ thì đầu tư thêm ko ra $ thì bỏ :D
     
  18. Luxifer

    Luxifer Sơ Nhập Giang Hồ

    Ah, tức là chưa triển khai. hehe. đang test local thì vọc cài thêm gì chả được. Good luck.
     
  19. money

    money Hương Chủ

    Tư vấn hay quá {brick}{brick}{brick}

    Nói thêm xíu: Cùng query đó mà bỏ ORDER BY thì chỉ còn 0.00088 giây đến khoảng 0.001xx giây

    Table của mình chỉ có:
    ID (bigint, PK Auto Increment)
    Name (varchar(255) fulltext index, unique index)
    Field 1(bigint -- index)
    Field 2(bigint -- index)
    Field 3(bigint -- index)
    Field 4(bigint -- index)
    Field 5(bigint -- index)
     
  20. money

    money Hương Chủ

    WHERE chỉ có trên 1 field Name có index unique và fulltext index rồi đó.
    Cùng 1 câu query, mình thử ko có ORDER BY thì tầm hơn 40 giây, còn bỏ ORDER BY ra thì còn 0.00xx giây thôi (trên DB > 80M rows và có khoảng 3M rows thỏa điều kiện WHERE)
    Nó bị chậm là do quá nhiều rows khớp điều kiện WHERE nên khi MySQL lấy dc các rows thỏa điều kiện nó bắt đầu SORT và chậm là từ đó.
    Do mình chỉ có 1 yêu cầu đặc thù là show ra 50 rows mới nhất trước (những rows có ID to nhất / hay rows insert sau cùng) nên mới hi vọng MySQL hỗ trợ sẵn cơ chế đó nhưng search thì lại ko thấy có :D