Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ricerca con % su ~tre milioni di righe.

0 views
Skip to first unread message

sathia

unread,
Nov 1, 2005, 10:34:34 AM11/1/05
to
Ciao, ho un database con tutte le città del mondo (se vi serve vi dico dove
scaricarlo, ha anche le posizioni geo) mi interesserebbe fare delle
ricerche sul campo city che è già un indice ovviamente.

solo che ad esempio se scrivo tur% ci mette 4/5 secondi (2389 record).
esiste un modo migliore per fare delle ricerche di questo tipo?

ho avuto un'idea bislaccca, (e immagino che mi prenderete in giro per
questo)

se creassi una tabella per ogni lettera dell'alfabeto

cities_a
cities_b
[...]

ne trarrei giovamento?

non so come fare altrimenti...

grazie per eventuali consigli.
--
chmod -R a-rwx The\ untouchables

giuseppe

unread,
Nov 1, 2005, 10:49:35 AM11/1/05
to
mi potresti dire dove scaricarlo ?


"sathia" <sathia...@libero.it> ha scritto nel messaggio
news:eWL9f.12197$hC1....@tornado.fastwebnet.it...

sathia

unread,
Nov 1, 2005, 11:22:18 AM11/1/05
to
giuseppe wrote:

> mi potresti dire dove scaricarlo ?

e un aiutino alla mia domanda almeno?

http://del.icio.us/sathia/world

;)

--
chmod -R a-w The\ untouchables

giuseppe

unread,
Nov 1, 2005, 11:32:42 AM11/1/05
to
> e un aiutino alla mia domanda almeno?

guarda, ci sono due casi:

a) fai una ricerca del tipo xyz%
e allora guadagni, perchè la sapendo già l'inziale fai una ricerca
approssimativamente su un numero di record pari a 1/24simo.

b) fai una ricerca del tipo %xyz o %xyz&
e allora non guadagni, perchè comunque si fa le tabelle dall'a alla z ;)


una sola cosa, in che formato l'hai importato quel file di testo?
se l'hai importanto in mysql, mi potresti spiegare che istruzioni hai usato
con INFILE ?

grazie e ciao!!!


sathia

unread,
Nov 1, 2005, 11:47:45 AM11/1/05
to
> a) fai una ricerca del tipo xyz%
> e allora guadagni, perchè la sapendo già l'inziale fai una ricerca
> approssimativamente su un numero di record pari a 1/24simo.
>
> b) fai una ricerca del tipo %xyz o %xyz&
> e allora non guadagni, perchè comunque si fa le tabelle dall'a alla z ;)
>

non ho capito molto

>
> una sola cosa, in che formato l'hai importato quel file di testo?
> se l'hai importanto in mysql, mi potresti spiegare che istruzioni hai
> usato con INFILE ?

eh, stavo impazzendo infatti mi sono fatto un file php al volo.
se lo trovo lo posto

>
> grazie e ciao!!!

sathia

unread,
Nov 1, 2005, 12:01:26 PM11/1/05
to

> una sola cosa, in che formato l'hai importato quel file di testo?
> se l'hai importanto in mysql, mi potresti spiegare che istruzioni hai
> usato con INFILE ?

nota che prima di parsarlo ho fatto un replace da vim
dei tab in ;

:% s/\t/;/g

tabella
CREATE TABLE `cities` (
`id` int(10) unsigned NOT NULL auto_increment,
`Country` varchar(255) NOT NULL default '',
`city` varchar(255) NOT NULL default '',
`Accent City` varchar(255) NOT NULL default '',
`Region` varchar(255) NOT NULL default '',
`latitude` varchar(255) NOT NULL default '',
`longitude` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`),
KEY `Country` (`Country`,`city`)
)

insert.php
<pre>
<?php
#error_reporting(E_ALL);
$db_host = "localhost";
$db_user = "user";
$db_password = "pass";
$db_name = "db";
$db = mysql_connect($db_host, $db_user, $db_password);
if ($db == FALSE)
die ("database errato");
mysql_select_db($db_name, $db)
or die ("Connessione al database errata");


$f = "/home/sathia/Desktop/cities.txt";
$lines = file($f);
foreach ($lines as $value) {

$part = explode(";",$value);

foreach($part as $val){

$partx .= "'".addslashes($val)."', ";

}

$partx = substr($partx,0,-2);

$SQL = "INSERT INTO cities VALUES (".$partx.")\n";
$partx = NULL;
//print($SQL);
//print($i++."\n");
mysql_query($SQL)or die(mysql_error());
}

?>

giuseppe

unread,
Nov 1, 2005, 12:01:47 PM11/1/05
to
>> a) fai una ricerca del tipo xyz%
>> e allora guadagni, perchè la sapendo già l'inziale fai una ricerca
>> approssimativamente su un numero di record pari a 1/24simo.
>>
>> b) fai una ricerca del tipo %xyz o %xyz&
>> e allora non guadagni, perchè comunque si fa le tabelle dall'a alla z ;)
>>
>
> non ho capito molto

allora, se dividi le città in base all'inziale, guadagni in velocità di
ricerca solo se quando fai la ricerca sai l'inziale della città.
esempio: 24.000 città nel db, 1.000 per ogni lettera dell'alfabeto (intesa
come iniziale della città).
se tu vuoi cercare ro%
allora guadagni, perchè puoi indicare in modo semplice nell'istruzione che
fa la ricerca di fare la ricerca sulla tabella città_r
e quindi, riportandoci all'esempio, fai la ricerca su 1000 entry invece che
su 24.000
se invece cerchi %oma
allora non guadagni nulla in velocità, perchè la ricerca la devi fare su
tutte le tabelle, e quindi fai la ricerca su 24.000 entry.


ora è più chiaro ?


>
>>
>> una sola cosa, in che formato l'hai importato quel file di testo?
>> se l'hai importanto in mysql, mi potresti spiegare che istruzioni hai
>> usato con INFILE ?
>
> eh, stavo impazzendo infatti mi sono fatto un file php al volo.
> se lo trovo lo posto

ti prego recupera quel. file perchè sto impazzendo :D


giuseppe

unread,
Nov 1, 2005, 12:04:34 PM11/1/05
to
> nota che prima di parsarlo ho fatto un replace da vim
> dei tab in ;

e come si fa?:D
perdona l'ignoranza :(


sathia

unread,
Nov 1, 2005, 12:06:24 PM11/1/05
to

> allora, se dividi le città in base all'inziale, guadagni in velocità di
> ricerca solo se quando fai la ricerca sai l'inziale della città.
> esempio: 24.000 città nel db, 1.000 per ogni lettera dell'alfabeto (intesa
> come iniziale della città).
> se tu vuoi cercare ro%
> allora guadagni, perchè puoi indicare in modo semplice nell'istruzione che
> fa la ricerca di fare la ricerca sulla tabella città_r
> e quindi, riportandoci all'esempio, fai la ricerca su 1000 entry invece
> che su 24.000
> se invece cerchi %oma
> allora non guadagni nulla in velocità, perchè la ricerca la devi fare su
> tutte le tabelle, e quindi fai la ricerca su 24.000 entry.
>
>
> ora è più chiaro ?

a grazie, ora ho capito.
ero partito dal presupposto che l'idea di splittare le tabelle fosse troppo
idiota!

non cercherò mai %oma solo %rom

farò dei test, anche se non mi sembra una cosa così furba

btw, ti ho postato il file php per tirare su il db.

ciaociao

sathia

unread,
Nov 1, 2005, 12:07:31 PM11/1/05
to
giuseppe wrote:

hai vim?

:% s/\t/;/g

schiacci : e poi copi esattamente dal : in poi

a quel punto puoi andare a farti un the e anche cena.

ciao ciao

Giuseppe Maxia

unread,
Nov 1, 2005, 12:08:05 PM11/1/05
to

Che bisogno c'era di fare sostituzioni?
si puo' fare tutto da SQL:

drop table if exists world_cities2;
create table world_cities2 (
id int not null auto_increment primary key,
Country_Code varchar(30),
City_Name varchar(100),
Accent_City_Name varchar(100),
State_Region varchar(100),
Population bigint,
Latitude float,
Longitude float,
key (City_Name)
);

load data local infile 'cities.txt' into table world_cities2
ignore 1 lines
(Country_Code, City_Name, Accent_City_Name, State_Region, Population, Latitude, Longitude)
;

E il motivo per cui la query e' lenta e' che hai un indice composto, ma usi solo
la seconda parte dell'indice. Prova a mettere un indice solo su citta' (oppure invertilo,
e metti citta+ nazione) e vedi che la velocita' cambia:

select count(*) from world_cities2 where city_name like 'ver%';
+----------+
| count(*) |
+----------+
| 6216 |
+----------+
1 row in set (0.02 sec)

select count(*) from world_cities2 where city_name like 'tur%';
+----------+
| count(*) |
+----------+
| 2849 |
+----------+
1 row in set (0.02 sec)

select count(*) from world_cities2 where city_name like 'ro%';
+----------+
| count(*) |
+----------+
| 17679 |
+----------+
1 row in set (0.05 sec)

ciao
gmax


--
_ _ _ _
(_|| | |(_|><
_|
http://gmax.oltrelinux.com

Giuseppe Maxia

unread,
Nov 1, 2005, 12:15:54 PM11/1/05
to
sathia wrote:
> giuseppe wrote:
>
>
>>>nota che prima di parsarlo ho fatto un replace da vim
>>>dei tab in ;
>>
>> e come si fa?:D
>>perdona l'ignoranza :(
>
>
> hai vim?
>
> :% s/\t/;/g
>
> schiacci : e poi copi esattamente dal : in poi
>
> a quel punto puoi andare a farti un the e anche cena.
>
> ciao ciao
>

Vim non e' fatto per questo tipo di lavoro. Non con un file di 138 MB.
Se proprio devi fare la sostituzione, e vuoi evitarti quel te', usa Perl:

$ time perl -i.bak -pe 's/\t/;/g' cities.txt

real 0m19.997s
user 0m18.900s
sys 0m0.850s

sathia

unread,
Nov 1, 2005, 12:16:10 PM11/1/05
to

> Che bisogno c'era di fare sostituzioni?

grazie per la risposta innanzi tutto.

dunque, da mysql non mi faceva caricare il file locale per motivi di
"sicurezza"
ho cercato su google, e le soluzioni erano abbastanza incasinate, quindi ho
fatto prima a fare a mano

> si puo' fare tutto da SQL:
>
> drop table if exists world_cities2;
> create table world_cities2 (
> id int not null auto_increment primary key,
> Country_Code varchar(30),
> City_Name varchar(100),
> Accent_City_Name varchar(100),
> State_Region varchar(100),
> Population bigint,
> Latitude float,
> Longitude float,
> key (City_Name)
> );
>
> load data local infile 'cities.txt' into table world_cities2
> ignore 1 lines
> (Country_Code, City_Name, Accent_City_Name, State_Region, Population,
> Latitude, Longitude) ;

adesso comunque ci riprovo.

>
> E il motivo per cui la query e' lenta e' che hai un indice composto, ma
> usi solo la seconda parte dell'indice. Prova a mettere un indice solo su
> citta' (oppure invertilo, e metti citta+ nazione) e vedi che la velocita'
> cambia:

avevo pensato a questa cosa, ma poi mi sono detto che sarebbe stata la
stessa cosa. ho sbagliato :)

grazie mille!

giuseppe

unread,
Nov 1, 2005, 12:18:33 PM11/1/05
to
giovani, ho windows, quindi non ho ne vim ne perl :(:(:(

come cacchio facciooooooooooooooooo


sathia

unread,
Nov 1, 2005, 12:20:37 PM11/1/05
to
> Vim non e' fatto per questo tipo di lavoro. Non con un file di 138 MB.
> Se proprio devi fare la sostituzione, e vuoi evitarti quel te', usa Perl:
>
> $ time perl -i.bak -pe 's/\t/;/g' cities.txt
>
> real 0m19.997s
> user 0m18.900s
> sys 0m0.850s
>
> ciao
> gmax
>

gmax, mi sento veramente un cane :/

grazie per i preziosissimi consigli!

sathia

unread,
Nov 1, 2005, 12:24:29 PM11/1/05
to

> select count(*) from world_cities2 where city_name like 'tur%';
> +----------+
> | count(*) |
> +----------+
> | 2849 |
> +----------+
> 1 row in set (0.02 sec)

Showing rows 0 - 29 (2849 total, Query took 0.0163 sec)

ti ringrazio infinitamente

Sat_

Giuseppe Maxia

unread,
Nov 1, 2005, 12:31:41 PM11/1/05
to
giuseppe wrote:
> giovani, ho windows, quindi non ho ne vim ne perl :(:(:(
>
> come cacchio facciooooooooooooooooo
>
>

A parte il fatto che non e' necessario fare la sostituzione,
(vedi l'altro post) su Windows non e' vietato installare Vim e Perl.

http://www.vim.org/download.php#pc
http://www.activestate.com/Products/ActivePerl/

giuseppe

unread,
Nov 1, 2005, 12:36:31 PM11/1/05
to
proprio non lo sapevo....
sto scaricando l'msi, poi eseguo l'istruzione che hai postato tu dal cmd ?


"Giuseppe Maxia" <gmax_@_cpan_._org> ha scritto nel messaggio
news:4367a67f$0$24635$4faf...@reader3.news.tin.it...

sathia

unread,
Nov 1, 2005, 12:53:00 PM11/1/05
to
sathia wrote:

>> Vim non e' fatto per questo tipo di lavoro. Non con un file di 138 MB.
>> Se proprio devi fare la sostituzione, e vuoi evitarti quel te', usa Perl:
>>
>> $ time perl -i.bak -pe 's/\t/;/g' cities.txt
>>
>> real 0m19.997s
>> user 0m18.900s
>> sys 0m0.850s
>>
>> ciao
>> gmax
>>

real 0m12.481s
user 0m9.222s
sys 0m0.885s

quanta potenza sprecata nelle mie mani... ;)

Enrico 'Henryx' Bianchi

unread,
Nov 1, 2005, 5:28:31 PM11/1/05
to
On Tue, 01 Nov 2005 16:34:34 +0100, sathia wrote:

> esiste un modo migliore per fare delle ricerche di questo tipo?

da quello che ne so, tutte le ricerche per LIKE disabilitano
eventuali indici sul campo. Inoltre, una divisione delle citta` per
lettera alfabetica, sarebbe inutile. Una possibile scrematura
potrebbe essere invece una suddivisione delle citta` per nazione (non
fosse altro per un fatto di ordinamento dei dati in maniera piu`
coerente). Infine, si, sono interessato al database :)

Henryx

Manlio Perillo

unread,
Nov 2, 2005, 4:00:50 AM11/2/05
to
On Tue, 01 Nov 2005 23:28:31 +0100, Enrico 'Henryx' Bianchi
<henryx.b...@libero.it> wrote:

>On Tue, 01 Nov 2005 16:34:34 +0100, sathia wrote:
>
>> esiste un modo migliore per fare delle ricerche di questo tipo?
>
>da quello che ne so, tutte le ricerche per LIKE disabilitano
>eventuali indici sul campo.

Per quanto riguarda PostgreSQL (almeno la 8.x):

"The optimizer can also use a B-tree index for queries involving the
pattern matching operators LIKE, ILIKE, ~, and ~*, if the pattern is
anchored to the beginning of the string, e.g., col LIKE 'foo%' or col
~ '^foo', but not col LIKE '%bar'"


Saluti Manlio Perillo

Sathia Musso

unread,
Nov 2, 2005, 5:33:32 AM11/2/05
to
> da quello che ne so, tutte le ricerche per LIKE disabilitano
> eventuali indici sul campo. Inoltre, una divisione delle citta` per
> lettera alfabetica, sarebbe inutile. Una possibile scrematura
> potrebbe essere invece una suddivisione delle citta` per nazione (non
> fosse altro per un fatto di ordinamento dei dati in maniera piu`
> coerente).

ora me la rileggo...

> Infine, si, sono interessato al database :)

http://del.icio.us/sathia/world

ci sono due miei bookmark. scaricali entrambe e scegli quello ch epiù ti
piace quello grosso è su max mind.

Sat_

>
> Henryx

--
chmod a-rwx The\ Untouchables.avi

Sathia Musso

unread,
Nov 2, 2005, 5:37:02 AM11/2/05
to
e cmq se usi il db guarda che meraviglia:

http://www.zipcodeworld.com/samples/distance.php.html

0 new messages