Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Truy vấn MySQL rất cụ thể mà tôi muốn cải thiện

Nếu bạn có một chỉ mục với created là cột hàng đầu, MySQL có thể thực hiện quét ngược. Nếu bạn có khoảng thời gian 24 giờ không có bất kỳ sự kiện nào, bạn có thể trả về một hàng KHÔNG có từ khoảng thời gian đó. Để đảm bảo rằng bạn đang có một hàng trong khoảng thời gian đó, bạn thực sự cần phải bao gồm một giới hạn thấp hơn trên created cũng như cột, một cái gì đó như thế này:

SELECT * FROM `eventos`
 WHERE ... 
   AND `created` <  FROM_UNIXTIME( {$timestamp} )
   AND `created` >= DATE_ADD(FROM_UNIXTIME( {$timestamp} ),INTERVAL -24 HOUR)
 ORDER BY `created` DESC
 LIMIT 1

Tôi nghĩ rằng chìa khóa quan trọng đối với hiệu suất ở đây là một chỉ mục với created là cột đầu tiên, cùng với tất cả (hoặc hầu hết) các cột khác được tham chiếu trong mệnh đề WHERE và đảm bảo rằng chỉ mục đó được sử dụng bởi truy vấn của bạn.

Nếu bạn cần một khoảng thời gian khác, hãy xuống giây, cách tiếp cận này có thể dễ dàng tổng quát hóa.

SELECT * FROM `eventos`
 WHERE ... 
   AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL  0*{$nsecs} SECOND)
   AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*{$nsecs} SECOND)
 ORDER BY `created` DESC
 LIMIT 1

Từ mã của bạn, có vẻ như khoảng thời gian 24 giờ được giới hạn tại một thời điểm tùy ý ... nếu hàm thời gian trả về ví dụ:1341580800 ('2012-07-06 13:20'), thì mười kỳ kinh của bạn sẽ từ 13:20 vào một ngày nhất định đến 13:20 ngày hôm sau.

(LƯU Ý:hãy đảm bảo rằng nếu tham số của bạn là một số nguyên dấu thời gian unix thì điều này đang được cơ sở dữ liệu diễn giải chính xác.)

Có thể hiệu quả hơn nếu kéo mười hàng trong một truy vấn. Nếu có sự đảm bảo rằng 'dấu thời gian' là duy nhất, thì bạn có thể tạo một truy vấn như vậy, nhưng văn bản truy vấn sẽ phức tạp hơn đáng kể so với những gì bạn hiện có. Chúng tôi có thể gặp rắc rối với việc nhận được MAX (timestamp_) trong mỗi khoảng thời gian và sau đó kết hợp trở lại để lấy hàng ... nhưng điều đó sẽ thực sự lộn xộn.

Nếu tôi định kéo tất cả mười hàng, có lẽ tôi sẽ thử với UNION ALL cách tiếp cận, không đẹp lắm, nhưng ít nhất nó có thể được điều chỉnh.

SELECT p0.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL  0*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p0 
 UNION ALL           
SELECT p1.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p1 
 UNION ALL           
SELECT p2.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -3*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p2 
 UNION ALL           
SELECT p3.*
  FROM ...

Một lần nữa, điều này có thể được tổng quát hóa, để chuyển qua một số giây như một đối số. Thay HOUR bằng SECOND và thay thế '24' bằng một tham số liên kết có số giây.

Nó khá dài, nhưng nó sẽ chạy ổn.

Một cách thực sự lộn xộn và phức tạp khác để lấy lại điều này trong một tập kết quả duy nhất là sử dụng chế độ xem nội tuyến để lấy dấu thời gian kết thúc cho mười khoảng thời gian, giống như sau:

     SELECT p.period_end
       FROM (SELECT DATE_ADD(t.t_,INTERVAL -1 * i.i_* {$nsecs} SECOND) AS period_end
               FROM (SELECT FROM_UNIXTIME( {$timestamp} ) AS t_) t
               JOIN (SELECT 0 AS i_
                     UNION ALL SELECT 1
                     UNION ALL SELECT 2
                     UNION ALL SELECT 3
                     UNION ALL SELECT 4
                     UNION ALL SELECT 5
                     UNION ALL SELECT 6
                     UNION ALL SELECT 7
                     UNION ALL SELECT 8
                     UNION ALL SELECT 9
                    ) i
            ) p

Và sau đó tham gia đó vào bàn của bạn ...

  ON `created` < p.period_end
 AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)

Và kéo lại MAX (đã tạo) cho mỗi khoảng thời gian GROUP BY p.period_end, bọc nó trong một chế độ xem nội tuyến.

Và sau đó nối nó trở lại bảng của bạn để lấy từng hàng.

Nhưng điều đó thực sự, thực sự lộn xộn, khó hiểu và không có khả năng nhanh hơn (hoặc hiệu quả hơn) so với những gì bạn đang làm. Cải tiến nhất mà bạn có thể thực hiện là thời gian cần thiết để chạy 9 truy vấn của bạn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng Mẫu hình thành đám mây để tạo các phiên bản MySQL trên RDS

  2. Phiên bản so với số lượng phân phối của MySQL

  3. Trả lại giá trị ngay cả khi không có kết quả

  4. Kiểm tra thời gian phản hồi trên thư đã gửi - có thể chỉ sử dụng SQL?

  5. MySQL CHỌN các hàng phù hợp với Mảng?