2011-09-25 46 views
5

Tôi có một bảng ID ID của InnoDB MySql Geo có ~ 1 triệu hàng. Các cấu trúc bảng là:Làm thế nào để tiếp tục tối ưu hóa bảng MySQL này cho một Truy vấn

CREATE TABLE `geoid` (
    `start_ip` int(11) NOT NULL, 
    `end_ip` int(11) NOT NULL, 
    `city` varchar(64) NOT NULL, 
    `region` char(2) NOT NULL, 
    PRIMARY KEY (`start_ip`,`end_ip`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Sẽ chỉ có một truy vấn kiểu chạy chống lại bảng này:

SELECT city, region FROM geoid WHERE 1259650516 BETWEEN start_ip AND end_ip 

Truy vấn này mất khoảng ~ 0,4228 giây, mà không phải là siêu chậm nhưng không cực kỳ nhanh chóng ête.

Câu hỏi của tôi là: Làm cách nào để tôi có thể tối ưu hóa bảng của mình cho truy vấn đơn lẻ này?

Tôi đã thử những điều sau đây:

  1. Thay đổi Công cụ lưu trữ để MyISAM, điều này làm cho các truy vấn mất khoảng 1,9 giây.
  2. Sử dụng câu lệnh WHERE 'WHERE geoid.start_ip < = 1259650516 AND 1259650516 < = geoid.end_ip'. Nhưng điều đó mất khoảng 0,5 giây để thực thi thay vì .4 ish.

Tôi đã xóa tất cả các hàng vô dụng khỏi bảng để làm cho nó nhỏ hơn. Tôi cần tất cả 1 triệu hàng.

CẬP NHẬT/GIẢI PHÁP

Nhờ bài viết dưới đây, đây là những gì tôi đã làm để khắc phục vấn đề này. (Chỉ cần để hoàn thành câu trả lời này cho bất cứ ai khác quan tâm)

Tôi đã thêm một cột mới vào bảng trên:

ALTER TABLE `geoid` ADD `geoip` LINESTRING NOT NULL 

tôi sau đó điền các cột mới với dữ liệu địa lý từ start_ip và end_ip

GeomFromText(CONCAT('LINESTRING(', start_ip, ' -1, ', end_ip, ' 1)')) 

sau đó tôi tạo chỉ mục không gian trên cột mới

CREATE SPATIAL INDEX geoip_index ON geoid(geoip); 

Từ đó, tất cả bạn phải làm là thay đổi truy vấn của mình thành:

SELECT city, region FROM geoid WHERE MBRContains(geoip, GeomFromText(CONCAT('POINT(', 1259650516, ' 0)'))); 

VÀ HOÀN CHỈNH CỦA BẠN. Thao tác này đã truy vấn từ .42 giây xuống còn .0003 giây !!!!!!!

Tôi thích INDEX này. Cảm ơn bạn. Hy vọng nó giúp.

+0

Bạn đã tạo chỉ mục 'SPATIAL' trên bảng' InnoDB'? – Quassnoi

+0

Tôi đã chuyển nó thành MyISAM trước. – RonSper

Trả lời

3

Thử thêm chỉ mục trên end_ip. Điều này sẽ làm cho truy vấn nhanh gấp đôi trong một số trường hợp.

Để có hiệu suất tốt hơn nhiều, bạn cần sử dụng chỉ mục SPATIAL, như được giải thích trong this article.

+1

Cũng giống như chính? Giống như: PRIMARY KEY ('start_ip',' end_ip'), KEY 'start_ip' (' start_ip'), KEY 'end_ip' (' end_ip'). Điều đó không thay đổi gì cả. – RonSper

+0

@Ron Sper: Vâng, nó sẽ không tăng tốc truy vấn trong mọi trường hợp, và nó chỉ cho một tốc độ tương đối nhỏ trong các trường hợp khác. Nếu bạn muốn hiệu suất tốt hơn nhiều, bạn có thể muốn xem xét một chỉ số SPATIAL. Xem bài viết này: http://explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql/. Nhưng nó không dành cho người mới bắt đầu. –

+1

WOW, đó là hoàn hảo. Đó là chính xác những gì tôi muốn. Cảm ơn bạn. – RonSper

0

Cố gắng tạo chỉ mục trên tất cả các trường được bao gồm trong truy vấn. trong trường hợp cụ thể này, hãy tạo một chỉ mục trên hai trường (start_ip và end_ip)

Các vấn đề liên quan