Kinerja Buruk saat menggunakan Indeks Spasial di MySQL

13

Posting ulang pertanyaan yang diajukan pada Stack Overflow ketika disarankan ini akan menjadi forum yang lebih baik.

Saya mencoba eksperimen kecil untuk mendorong kumpulan data yang tidak bersifat geo-spasial tetapi sangat cocok dan saya menemukan hasilnya agak meresahkan. Kumpulan data adalah data genomik, misalnya Genom Manusia di mana kami memiliki wilayah DNA tempat elemen-elemen seperti gen menempati koordinat awal dan berhenti yang spesifik (sumbu X kami). Kami memiliki banyak wilayah DNA (kromosom) yang menempati sumbu Y. Tujuannya adalah untuk mengembalikan semua item yang memotong dua koordinat X sepanjang koordinat Y tunggal, misalnya LineString (MULAI 1, END 2).

Teorinya kelihatannya bagus jadi saya mendorongnya ke proyek genom berbasis MySQL yang ada dan muncul dengan struktur tabel seperti:

CREATE TABLE `spatial_feature` (
  `spatial_feature_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `external_id` int(10) unsigned NOT NULL,
  `external_type` int(3) unsigned NOT NULL,
  `location` geometry NOT NULL,
  PRIMARY KEY (`spatial_feature_id`),
  SPATIAL KEY `sf_location_idx` (`location`)
) ENGINE=MyISAM;

external_idmewakili pengenal entitas yang telah kami enkode ke dalam tabel ini & external_typemengkodekan sumbernya. Semuanya tampak bagus dan saya mendorong beberapa data awal (30.000 baris) yang tampaknya bekerja dengan baik. Ketika ini meningkat melewati tanda 3 juta baris, MySQL menolak untuk menggunakan indeks spasial dan lebih lambat ketika dipaksa untuk menggunakannya (40 detik vs 5 detik menggunakan pemindaian tabel penuh). Ketika lebih banyak data ditambahkan indeks mulai digunakan tetapi penalti kinerja tetap ada. Memaksa indeks mati membuat kueri menjadi 8 detik. Kueri yang saya gunakan terlihat seperti:

select count(*)
from spatial_feature
where MBRIntersects(GeomFromText('LineString(7420023 1, 7420023 1)'), location);

Data yang masuk ke ini sangat padat di sepanjang dimensi Y (anggaplah seperti Anda telah mencatat posisi setiap bangunan, kotak telepon, kotak pos, dan merpati di jalan yang sangat panjang). Saya telah melakukan tes tentang bagaimana R-Indexes berperilaku dengan data ini di Java dan juga orang lain di lapangan telah menerapkannya ke format flat-file dengan sukses. Namun tidak ada yang menerapkannya pada basis data AFAIK yang merupakan tujuan dari tes ini.

Adakah yang melihat perilaku serupa ketika menambahkan data dalam jumlah besar ke model spasial yang tidak terlalu berbeda di sepanjang sumbu tertentu? Masalahnya tetap ada jika saya membalikkan penggunaan koordinat. Saya menjalankan pengaturan berikut jika itu penyebabnya

  • MacOS 10.6.6
  • MySQL 5.1.46
andeyatz
sumber

Jawaban:

5

MySQL, seperti PostGIS, menyimpan data indeks spasial dalam struktur R-tree sehingga dapat menemukan hal-hal dengan cepat. R-tree, seperti B-tree, diatur sedemikian rupa sehingga dioptimalkan untuk mengambil hanya sebagian kecil dari total data dalam tabel. Sebenarnya lebih cepat untuk mengabaikan indeks untuk pertanyaan yang perlu membaca sebagian besar tabel untuk mengembalikan data atau melakukan penggabungan besar, kasus klasik yang menimbulkan banyak forum [poster] forum mengeluh tentang permintaan yang mengembalikan setengah dari mereka tabel "tidak menggunakan indeks baru yang baru saja mereka buat."

Dari http://rickonrails.wordpress.com/2009/03/30/big-ole-mysql-spatial-table-optimization-tricks/

Jika Anda bisa memasukkan semua data tabel Anda ke dalam memori, kinerja Anda baik. Jika / ketika Anda perlu mulai membaca disk, kinerjanya cepat memburuk. Apakah Anda melakukan pola penggunaan memori contoh mysql Anda untuk dua kasus: baris 30k vs baris 3000k?

tmarthal
sumber
Saya pikir ini bisa lebih dekat dengan masalah ini. TBH ini adalah R-index yang saya inginkan; matematika spasial lainnya adalah bonus yang bagus karena itu harus dilakukan di lapisan API di bawah sistem yang lama. Saya memang mencoba sedikit penyetelan tetapi meningkatkan buffer kunci tidak membantu (buffer lain tidak akan membantu di sini seperti buffer tabel karena ini adalah 1 tabel permintaan di server pribadi saya). Apa yang aneh adalah bahwa MySQL memalu mesin saya ke tanah ketika query dijalankan (100% selama menjalankan query). Yang mengatakan melakukan pemindaian tabel penuh jadi mungkin itu tidak aneh
andeyatz
5

Pasti ada yang salah dengan instalasi mysql Anda atau pengaturan .ini. Baru saja menguji indeks geospasial pada mac lama saya (10.6.8 / MySQL 5.2). Konfigurasi itu mirip dengan milik Anda dan saya menguji dump geodata besar ( 9 juta catatan ). Saya melakukan permintaan ini:

SET @radius = 30;
SET @center = GeomFromText('POINT(51.51359 7.465425)');
SET @r = @radius/69.1;
SET @bbox = CONCAT('POLYGON((', 
  X(@center) - @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) - @r, '))' 
);

SELECT geonameid, SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 ))*69.1 
AS distance
FROM TABLENAME AS root
WHERE Intersects( point, GeomFromText(@bbox) ) 
AND SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 )) < @r 
ORDER BY distance; 

Hanya butuh 0,0336 detik.

Saya menggunakan query di atas misalnya untuk perbandingan antara tabel di mana tabel di mana hanya nilai lat / lng untuk @center berasal memiliki INDEX polos dari city_latitude / city_longitude dan 9-12 Mio. tabel dari geonames.org memiliki indeks geospasial.

Dan saya hanya ingin menambahkan bahwa ketika ada yang memasukkan data besar dalam sebuah tabel, mungkin akan lebih baik untuk menambahkan indeks setelah INSERT. Jika tidak, akan lebih lama untuk setiap baris yang Anda tambahkan ... [tetapi itu tidak penting]

sebilasse
sumber
Wow, itu sangat bagus. Sekarang saya tidak yakin apa yang saya lakukan salah dalam tes saya sendiri. Satu hal yang mungkin menyebabkan masalah adalah sifat set data saya dibandingkan dengan set data geospasial yang lebih tradisional. Yang mengatakan saya hanya menebak dan tidak punya dasar untuk ini. Sangat brilian untuk melihat bahwa Anda tidak perlu memaksakan indeks ke dalam memori untuk mendapatkan kecepatan.
andeyatz
Klausa WHERE dengan jari-jari bisa memfilter sebagian besar tabel dari menggunakan indeks.
tmarthal
2

Pernahkah Anda berpikir untuk memecahnya menjadi dua kolom 1D alih-alih satu kolom 2D?

Pengoptimal dapat tersedak pada semua data yang serupa dan memiliki dua kolom dengan variasi yang lebih besar mungkin membantu.

Yang mungkin juga Anda periksa adalah urutan pemeriksaan item. Saya punya masalah di Oracle Spatial di mana saya mencari di Nama Belakang dan filter IN_REGION. Oracle memutuskan cara tercepat adalah dengan menggunakan nama belakang dan kemudian melakukan pemeriksaan wilayah. Biarkan saya memberitahu Anda, melakukan cek di wilayah pada semua Robinson di Cleveland lambat . Saya ingat saya harus melewati argumen khusus Oracle untuk memaksanya menggunakan indeks spasial terlebih dahulu.

Mark Robinson
sumber
Sayangnya 1 dimensi jauh lebih sedikit populasi daripada dimensi lain. Untuk memasukkan ini ke dalam konteks, genom manusia memiliki 24 kromosom unik (22 pasang dan dua kromosom seks) bersama dengan sekumpulan data yang telah dikumpulkan ke tingkat yang berbeda. Yang berarti jika Anda memetakan elemen ke kasus penggunaan dasar yang hanya 24 pengidentifikasi unik dalam satu dimensi. Harapan semula adalah bahwa indeks R-tree akan mampu melakukan tidak hanya lebih banyak performan tumpang tindih rentang pemeriksaan tetapi juga membedakan antara wilayah-wilayah ini dalam satu permintaan.
andeyatz