phpbar.de logo

Mailinglisten-Archive

[php] Re: [php] Logische =?iso-8859-1?Q?UND=2DVerkn=FCpfung?=

[php] Re: [php] Logische =?iso-8859-1?Q?UND=2DVerkn=FCpfung?=

Kristian =?iso-8859-1?Q?K=F6hntopp?= kk_(at)_netuse.de
Tue, 30 Nov 1999 16:41:20 +0100


Adi Sieker wrote:
> select ...... where
>           beschreibung like "%Autos%"
>        and
>           beschreibung like "%LKWS%"
> 
> oder, gibt noch eine elegantere lösung??

Jede andere Lösung, bei der die Datenbank Indices benutzen kann,
wäre eleganter. Bei der hier vorgestellten Lösung wird eine LIKE-
Anweisung mit einem Wildcard am Anfang des Suchbegriffes verwendet.
Wie man sich leicht überlegen kann, kann bei einer solchen
Query ein Index nicht verwendet werden.

Wenn man es sich nicht überlegen kann, findet man den 
entsprechenden Hinweis im Handbuch seiner Datenbank oder
indem man es ausprobiert:

mysql> desc applications;
+--------------+-----------------+------+-----+---------+----------------+
| Field        | Type            | Null | Key | Default | Extra          |
+--------------+-----------------+------+-----+---------+----------------+
| appnr        | int(11)         |      | PRI | 0       | auto_increment |
...
+--------------+-----------------+------+-----+---------+----------------+
mysql> explain select * from applications where appnr like "%1%";
+--------------+------+---------------+------+---------+------+------+------------+
| table        | type | possible_keys | key  | key_len | ref  | rows | Extra      |
+--------------+------+---------------+------+---------+------+------+------------+
| applications | ALL  | NULL          | NULL |    NULL | NULL |   38 | where used |
+--------------+------+---------------+------+---------+------+------+------------+
1 row in set (0.01 sec)
mysql> explain select * from applications where appnr like "1%";
+--------------+------+---------------+------+---------+------+------+------------+
| table        | type | possible_keys | key  | key_len | ref  | rows | Extra      |
+--------------+------+---------------+------+---------+------+------+------------+
| applications | ALL  | PRIMARY       | NULL |    NULL | NULL |   38 | where used |
+--------------+------+---------------+------+---------+------+------+------------+
1 row in set (0.00 sec)

Wie man sieht, wird in der 2. Query die Verwendung des Keys ermöglicht, in der 1. Query jedoch wegen des führenden Wildcard nicht.


Die Query wird genau dann effizient, wenn man eine Tabelle Produkte
normalisiert, indem man eine Tabelle Suchbegriffe erzeugt, sodaß
eine 1:n Beziehung zwischen Produkten und Suchbegriffen entsteht.

create table suchbegriffe (
  such_id integer not null primary key auto_increment,
  produkt_id integer not null,
  suchbegriff varchar(80) not null,
  index (produkt_id),
  index(suchbegriff)
);

Nun kann man

select * from produkte as p, suchbegriffe as s 
  where p.produkt_id = s.produkt.id
  and ( s.suchbegriff = "a" or s.suchbegriff = "b" );

abfahren.

Auf p.produkt_id ist ein Index, weil es sich um einen PK handelt.
Der zugehörige FK s.produkt_id ist ebenfalls indiziert worden.
Um die Suche zu beschleunigen, ist s.suchbegriff indiziert und
wird ohne führende Wildcards verwendet. Ohne nachlaufende Wildcards
kann sogar eine eqref ("=") statt eines Patternmatches verwendet
werden, was die Sache noch schneller macht.

Dies ist relational korrekt und schneller als Deine Anfrage, also
ist es wohl "eleganter".

Kristian

-- 
Kristian Köhntopp, NetUSE Kommunikationstechnologie GmbH
Siemenswall, D-24107 Kiel, Germany, +49 431 386 436 00
Using PHP3? See our web development library at
http://phplib.netuse.de/ (We have moved! Update your bookmarks!)


php::bar PHP Wiki   -   Listenarchive