2016-04-14 28 views
0

Bir müşterinin alt grubuna en yakın müşteriyi almaya çalışıyoruz. SQL'imiz beklendiği gibi çalışır, ancak küçük bir test veritabanı (4,000 müşteri, 50 cust alt kümesi) için bile birkaç saniye sürer ve veritabanı boyutu gibi dramatik bir şekilde artar.SQL'de mesafe hesaplama nasıl geliştirilir

select ... custA data, custB data 
from customers custA 
left join customers custB on custB.id= 
    (select custC.id 
     from customers custC 
     where custC.id<>custA.id 
     order by distance(custA.lat,custA.lon,custC.lat,custC.lon) asc limit 1) 
where ... custA conditions 

mesafe, böylece aynı durumda ya da benzer sadece müşteriler karşılaştırmak için filtrenin çeşit arama ... ya da koyabilirsiniz o isim önerir :) Elbette

tam olarak ne hesaplayan bir fonksiyondur lat veya lon ... vs farklılığı maksimum, ancak sql yapısını geliştirmek için herhangi bir yolu var mı?

Thks

cevap

0

Senin soruna bir önerim var. Müşteriler tablonuzu taklit etmek ve bir taklit verilerle doldurmak için bir tablo değişkeni kullanıyorum. Basit nedenlerden ötürü mesafe fonksiyonunun kullanımını kaldırdım ancak çevrenizde kolayca değiştirebilirsiniz.

Ben TOP ile iç sorgu yerine ROW_NUMBER yararlanarak am 1 Çözümümün SQL Server için yazılmıştır

:

create table customers (
    id int identity(1,1), 
    distance int 
) 
go 


insert into customers values(10) 
insert into customers values(100) 
insert into customers values(20) 
insert into customers values(30) 
insert into customers values(40) 
insert into customers values(50) 
insert into customers values(60) 
go 

create view AllCustomerDistances with SCHEMABINDING 
as 
select custA.Id custA_Id, custC.Id custC_id, custA.distance - custC.distance [distanceBetweenAandC] --distance(custA.lat, custA.lon, custC.lon, custC.lon) [distanceBetweenAandC] 
from 
    dbo.customers custA cross join 
    dbo.customers custC 
where 
    custA.Id <> custC.Id 

go 

select * 
from 
( select 
     custA.Id [A], 
     custB.Id [B], 
     row_number() over (partition by custA_Id order by distanceBetweenAandC desc) as Rownumber 
    from 
    AllCustomerDistances d inner join 
     customers custA on (d.custA_Id = custA.Id) inner join 
     customers custb on (d.custC_Id = custb.Id) 
) r 
where 
    Rownumber = 1 

Benim alt sorgu tüm müşteriler ve ROW_NUMBER arasındaki mesafeleri hesaplar fonksiyon mesafelere göre sipariş vermemi ve sadece daha küçük kombinasyonu seçmemi sağlıyor.

DÜZENLEME: Artık mesafeleri hesaplamak ve sql sunucusunda depolamak için bir görünüm kullanıyorum. SCHEMABINDING seçeneğiyle kullanmak, sql sunucunun görünümü önceden işlemesine izin verir, böylece görünüme yapılan çoklu çağrılar çok daha hızlı bir sorguyla sonuçlanır. Etki, sorgunuzu ilk kez çalıştırdığınızda gerçekleşir. Başvurulan kayıtlar değiştiğinde görünüm otomatik olarak güncellenecektir.

+0

İlk sözdizimi geliştirmemesine rağmen, ilginç bir fikir için teşekkürler. Bunu test ettik ve orjinalinin 1,6 ila 1,8 katı arasında değişiyor ... müşterinin alt kümeleri artacak, ilişki daha da kötüye gidiyor. – DeepButi

+0

Cevabımı düzenledim ve şimdi bir Dizine Eklenmiş Görünüm kullanıyor. Bu durumun sizin durumunuzda kullanılıp kullanılamayacağından emin değilim, ancak sorgunuzu öldüren kişi, sorgunuzu her çalıştırdığınızda müşteriler arasındaki mesafeyi hesaplamak için gereken süredir. indekslenmiş bir görünümle, bu görünüm ilk kez gerçekleştiğinde gerçekleşir. –

+0

Öneriniz için teşekkürler. Bir Postgress veritabanı kullanıyoruz ve en benzer konsept MATERIALIZED bir görünüm olacaktır. Malzeme tabloları, görünüm verileri kaynak tabloları güncellenmedikçe periyodik bir süreçle açıkça yeniden oluşturulmalıdır. Milyonlarca kayıt içerecek şekilde bir üretim sistemindeki tüm görüşü oluşturmak için gereken süreden emin değilsiniz (tüm müşteri masasının kendisi ile çapraz birleştirme). Biz bunu deneyeceğiz. – DeepButi