Demo

Probiere ClanSphere aus und teste daran herum. Demo


Antworten: 6
Seite [1]
pico


Beginner




Beiträge: 7
# Thema - 02.02.2012 um 17:42 Uhr
Soooo, die Expedition ClanSphere + SQL Server geht weiter.

Unter SQL Server funktioniert die Pagination (also Ergebnisse ab $first zurückgeben) nicht. Die zweite Seite der News auszugeben erzeugt etwa folgenden Fehler (einiges ausgelassen mit [...]):
Error: [...]\mods\news\recent.php -> cs_sql_select - 156 - [Microsoft][SQL Server Native Client 10.0][SQL Server]Incorrect syntax near the keyword 'ORDER'. --Query: SELECT TOP 8 [...] FROM cs_news nws INNER JOIN cs_users usr ON nws.users_id = usr.users_id INNER JOIN cs_categories cat ON nws.categories_id = cat.categories_id WHERE (news_id NOT IN ([...])) AND (hier knallt's) ORDER BY news_attached DESC, news_time DESC

Der Fehler wäre verhältnismäßig leicht zu beheben:
Zeile 180 in sqlsrv.php:
$sql_where = empty($sql_where) ? $sql_notin : $sql_notin . ' AND ';
ändern in:
$sql_where = empty($sql_where) ? $sql_notin : $sql_notin . ' AND '. $sql_where;


ABER:
Auf die Art zu pagen ist ineffizient. Ich weiß, dass paging in mySQL leicht ist (mit limit). Im SQL Server funktioniert es etwas komplizierter, nämlich über common table expressions. Das Grundgerüst lautet:

 
1.
2.
3.
4.
5.
1. / 2. / ... 
 WITH SomeName AS 

SELECT [Spalten], ROW_NUMBER() OVER (ORDER BY [Sortierung]) as ZeilenNummer FROM [TabellenWHERE [Bedingung]
)
SELECT FROM SomeName WHERE ZeilenNummer>= $first AND ZeilenNummer $first $max


wobei $first hier 1-basiert ist, nicht 0-basiert. $first = 1 ist also die erste Zeile.

In dieser Variante sieht z.B. die Query für die zweite Newsseite so aus:
 
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
1. / 2. / ... 
 
WITH temp_cte 
AS 
(
    
SELECT nws.news_id AS news_id
    
nws.news_headline AS news_headline
    
nws.news_time AS news_time,
    
nws.news_text AS news_text
    
nws.news_pictures AS news_pictures
    
nws.users_id AS users_id
    
usr.users_nick AS users_nick
    
usr.users_active AS users_active
    
usr.users_delete AS users_delete
    
nws.categories_id AS categories_id,
    
cat.categories_picture AS categories_picture
    
cat.categories_name AS categories_name
    
nws.news_mirror AS news_mirror
    
nws.news_mirror_name AS news_mirror_name
    
nws.news_readmore AS news_readmore
    
nws.news_readmore_active AS news_readmore_active
    
ROW_NUMBER() OVER (ORDER BY news_attached DESCnews_time DESC) as _rowNum 
    FROM cs_news nws 
        INNER JOIN cs_users usr ON nws
.users_id usr.users_id 
        INNER JOIN cs_categories cat ON nws
.categories_id cat.categories_id 
    WHERE nws
.news_public AND cat.categories_access <= 5
)
SELECT 
FROM temp_cte 
WHERE _rowNum 
>= 
  
AND _rowNum 17



Ich habe einen patch angefügt, der cs_sql_select für den SQL Server entsprechend anpasst. Erste Tests sind positiv, alles scheint zu funktionieren. Sollte es doch noch mal irgendwo krachen, melde ich mich.
Dateianhänge:
patch paging.patch (2.54 KiB - 23 mal heruntergeladen )


Zuletzt editiert von pico am 02.02.2012 um 17:48 Uhr (2x Editiert)
Inaktiv
hajo ClanSphere Team


VIP - Poster




Herkunft: Barsbüttel
Beiträge: 9411
# Antwort: 1 - 02.02.2012 um 18:19 Uhr
ich verwende vorerst mal den ineffizienten und einfachen fix, danke dafür.

beim anderen würd ich gern im detail wissen ob dieser a) andere voraussetzungen an die mindestversion / umgebung hat oder b) eventuelle seiteneffekte auftreten können. falls nicht könnte man dies in kürze auch noch nachrüsten.

das paging funktioniert ja leider nichtnur in mysql, sondern auch bei postgresql und sqlite etwaig genauso einfach. der support für (pdo_)sqlsrv ist eigentlich auch nur eine portierung dessen von der mssql erweiterung damals, in der das auch schon so gelöst war.


------------------
ClanSphere - professional clan care starts here

Inaktiv
|
pico
Thread-Ersteller


Beginner




Beiträge: 7
# Antwort: 2 - 02.02.2012 um 19:29 Uhr
02.02.2012 um 18:19 Uhr - hajo:
ich verwende vorerst mal den ineffizienten und einfachen fix, danke dafür.

Gerne


beim anderen würd ich gern im detail wissen ob dieser a) andere voraussetzungen an die mindestversion / umgebung hat oder b) eventuelle seiteneffekte auftreten können. falls nicht könnte man dies in kürze auch noch nachrüsten.

Das funktioniert ab SQL Server 2005, deckt sich also mit den Voraussetzungen, die ihr schon stellt. "Seiteneffekte" hat das keine, es ist lediglich die "korrekte" Art für Paging in SQL Server und wird z.B. auch von Object-Relational-Mappern wie (N)Hibernate so verwendet. Es ist auch deutlich effizienter, da SQL Server besser versteht, was gemeint ist und entsprechend optimieren kann. Vergleicht z.B. mal die Query-Pläne beider Versionen.

Ich muss euch aber erst einmal ein Lob aussprechen, dass ihr überhaupt SQL Server unterstützt. Leider werden viele PHP Anwendungen nur für MySQL angeboten.

Grüße,
pico


Inaktiv
|
Deaktiviert

Supporter
Supporter



Beiträge: 1287
# Antwort: 3 - 02.02.2012 um 19:32 Uhr
Ich denke, dass liegt aber vorallem dadran, dass SQL Server nicht sonderlich verbreitet sind. Such doch mal nach Webspace/-server welche SQL integriert haben.

Aber ja, ich finds auch gut, dass eine solch breite Masse vorhanden ist.


Inaktiv
|
hajo ClanSphere Team


VIP - Poster




Herkunft: Barsbüttel
Beiträge: 9411
# Antwort: 4 - 02.02.2012 um 19:33 Uhr
rudimentären support für oracle und ibm db2 gabs auch mal testweise aber nie produktiv. ist halt alles simpel gestrickt in einer art crud-toolbox. orms mag ich aufgrund ihrer komplexität nicht wirklich anfassen, dann lieber gleich eine objektorientierte db oder zumindest schnittstelle wie bei postgresql.

deine bessere variante vom patch spiel ich sonst am wochenende mal ein, wenn bis dahin keine probleme damit auftauchen.


------------------
ClanSphere - professional clan care starts here

Zuletzt editiert von hajo ClanSphere Team am 02.02.2012 um 19:35 Uhr (1x Editiert)
Inaktiv
|
pico
Thread-Ersteller


Beginner




Beiträge: 7
# Antwort: 5 - 02.02.2012 um 20:44 Uhr
02.02.2012 um 19:32 Uhr - Schalla:
Ich denke, dass liegt aber vorallem dadran, dass SQL Server nicht sonderlich verbreitet sind. Such doch mal nach Webspace/-server welche SQL integriert haben.

Naja, das liegt immer daran, wo man sucht. Im Business Umfeld sind Windows Server und SQL Server (und auch z.B. Oracle) doch recht stark verbreitet. Im (ich nenne es mal) "Hobby" Bereich domiert gefühlt natürlich Linux/Apache/MySQL/PHP*. Ich bin selbständiger Softwareentwickler und entwickle meistens browsergestützte .NET oder Java Intranetanwendungen für Unternehmen, da steht gerne auch mal eine Windows Server Maschine im Serverraum.

Stichwort ORM: die sind mMn ein wahrer Segen. Ich weiß nicht, wann ich das letzte Mal eine SQL Query in einer meiner Anwendungen tatsächlich selbst geschrieben habe. Irgendwie muss man die Daten ja doch zwischen DB und Anwendung hin und herschieben - ein ORM macht das einfacher, sicherer und besser wartbar (Stichwort: Refactoring).

Und sie motivieren auch dazu, die Schichten in der Anwendung sauber zu trennen. Es ist nicht böse gemeint, aber man sieht ClanSphere halt schon an, dass es eine typische PHP Anwendung ist. Da werden in einem Atemzug SQL Queries zusammengestöpselt und drei Zeilen weiter HTML Code erzeugt. Dass das eine Wartung schwer macht sieht man z.B. an den double quotes. Mit parametrisierten Queries und/oder einem ORM und einer Architektur, die die Aufgaben besser trennt (etwa MVC) wäre das Problem gar nicht aufgetaucht oder einfacher zu lösen. Außerdem ist das zusammen Stecken von Queries aus Strings fehleranfällig bis gefährlich (SQL Injection).

Nur mal als Beispiel:
Um die letzten News und deren Anzahl abzufragen (ohne ggf. eine Vorauswahl der Kategorie), Code in ClanSphere:
 
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
1. / 2. / ... 
 
$where 
"nws.news_public = 1 AND cat.categories_access <= " $account['access_news'];

$join 'news nws INNER JOIN {pre}_categories cat ON nws.categories_id = cat.categories_id';
$news_count cs_sql_count(__FILE__$join$where'news_id');

$from 'news nws INNER JOIN {pre}_users usr ON nws.users_id = usr.users_id ';
$from .= 'INNER JOIN {pre}_categories cat ON nws.categories_id = cat.categories_id';
$select 'nws.news_id AS news_id, nws.news_headline AS news_headline, nws.news_time AS news_time, nws.news_text AS news_text,';
$select .= ' nws.news_pictures AS news_pictures, nws.users_id AS users_id, usr.users_nick AS users_nick, usr.users_active AS users_active, usr.users_delete AS users_delete, nws.categories_id AS ';
$select .= 'categories_id, cat.categories_picture AS categories_picture, cat.categories_name AS categories_name, nws.news_mirror AS news_mirror, nws.news_mirror_name AS news_mirror_name, nws.news_readmore AS news_readmore, nws.news_readmore_active AS news_readmore_active';
$order 'news_attached DESC, news_time DESC';
$cs_news cs_sql_select(__FILE__$from$select$where$order$start$cs_option['max_recent']);


Das ist noch nicht einmal ein Extrembeispiel, ich habe Stellen gesehen, die noch mehr das Prädikat "Spagetti-Code" verdienen

vs. Einsatz eines ORM (hier ein Beispiel, wie es in C# mit NHibernate aussehen könnte. News, Category und Account wären Klassen):

 
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
1. / 2. / ... 
 
var query database.QueryOver<News>();

query.Where(news => news.IsPublished)
    .
JoinQueryOver(news => news.Category)
    .
Where(cat => cat.Access account.AccessNews);

var 
countQuery query.ToRowCountQuery().FutureValue<int>();

var 
selectedNewsQuery query.OrderBy(news => news.Access).Desc
    
.ThenBy(news => news.Time).Desc
    
.Skip(first)
    .
Take(max)
    .
Future();

var 
count countQuery.Value;
var 
selectedNews selectedNewsQuery.ToArray();

Welches Datenbanksystem verwendet wird, ist egal, da alle Unterschiede im ORM gekapselt sind. Änderungen im Mapping können zentral bearbeitet werden und beeinflussen Codestellen wie diese nicht. Refactorings (also z.B. Umbenennung von Variablennamen) können problemlos mit einem Refactoring-Tool durchgeführt werden, weil nirgendwo Strings verwendet werden.

Aber wie gesagt, ich schreibe das nicht, um eure Codebase schlecht zu machen. Ich möchte nur die Vorzüge von "sauberem" Code andeuten. Ich denke, dass ClanSphere eine gute und nützliche Idee ist - sonst hätte ich es nicht installiert. Vielleicht kann ich ja dazu beitragen, es noch zu verbessern.


Inaktiv
|
hajo ClanSphere Team


VIP - Poster




Herkunft: Barsbüttel
Beiträge: 9411
# Antwort: 6 - 02.02.2012 um 20:51 Uhr
für einen nachfolger hatte ich in jedem fall vor stored procedures und prepared statements zu verwenden, an ein orm allerdings weiterhin nicht gedacht. mir kam eher eine auslagerung der logik richtung db in form von triggern und views in den sinn.

was orms angeht gibt es ja auch für php diverse vertreter wie z.b. doctrine und propel, aber damit habe ich mich nur oberflächlich auseinandergesetzt bislang.

die codebase von clansphere ist eben noch typischer php 4.x quelltext mit nahezu keinen kommentaren, unit tests, usw. da kann man nichts dran schlechter reden als es eh schon ist


------------------
ClanSphere - professional clan care starts here

Zuletzt editiert von hajo ClanSphere Team am 02.02.2012 um 20:52 Uhr (1x Editiert)
Inaktiv
|
Antworten: 6
Seite [1]


Sie müssen sich registrieren, um zu antworten.