2016-10-28 1 views
0

Ich habe eine Datenbank mit Millionen von Datensätzen. Die Tabelle ist wie:Milion Record Sql Sortieren nach und Zeilen zählen


Tabellenname: Datensatz

Filed1: Name (VARCHAR) (Primärschlüssel)

Field2: Record (int/Bigint)

Beispiel:

Name | Notieren

Darrin | 256

Aaron | 3

Daryl | 12

...


Ich muss wissen, welche Position die Benutzer mit dem Namen bedeutet 'Namex' in sortierter Datensätze.

Derzeit implementieren ich diese Lösung:

... 

$name=namex; 
$query= mysqli_query($mysqli,"SELECT Name FROM record ORDER BY Record DESC"); 

$x=0; 
$rank=0; 
if ($query->num_rows > 0) { 
    // output data of each row 
    while($row = $query->fetch_assoc()) { 
     if($row["Name"]==$name){ 
      $rank=$x+1; 
      echo "Rank : $rank<br>"; 

      break; 
     } 


     $x++; 
    } 
} 

... 

Mit ihm und 1 Million Datensätze in der Datenbank, die Antwort in etwa 4 Sekunden kommt.

Ich habe versucht, einen Tabellenindex auf das Feld Record setzen, aber die gleiche Leistung geblieben sind.

Wie kann ich die Ausführungszeiten reduzieren?

+1

'SELECT COUNT (Name) als Rang von Rekord WHERE name <= $ name' vielleicht ... natürlich Sie müssen die Abfrage parametrisieren, um Risiken der SQL-Injektion zu vermeiden –

+1

Sie sollten wirklich eine 'where' Klausel verwenden. Du legst LITERAL das Äquivalent dazu an, zu einem Walmart zu fahren, das GESAMTE Inventar des Ladens aufzukaufen, es nach Hause zu fahren, es dann durchzusuchen und alles wegzuwerfen, außer dem Schokoriegel, den du haben wolltest. –

+0

@MarkBaker außer er hat ORDER BY Record, nicht Name –

Antwort

1

Da ich weiß nicht, was DBMS Sie verwenden (in Tags, die Sie sowohl MySQL und SQL-Server verwenden ...), können Sie erstellen Sie eine Ansicht (für SQL-Server haben eine sein indexed view) oder für mysql implementieren/emulieren eine Art materialisierte Ansicht (hat eine bessere Leistung). Die Ansicht ist gut, um durch einige DBMS eine bessere Leistung zu erzielen. Für MySQL kann es keinen Unterschied geben.

Nach Ansicht zeigen den Rang Position als Abfrage unter (mysql Beispiel):

CREATE VIEW ranked_record AS 
SELECT 
    record.Name, 
    @curRank := @curRank + 1 AS rank 
FROM 
    record, 
    (SELECT @curRank := 0) r 
ORDER BY Record DESC; 

oder SQL Server:

CREATE VIEW ranked_record AS 
SELECT 
    record.Name, 
    row_number() over(ORDER BY record) 
FROM 
    record; 

Und nur Ihre Abfrage:

SELECT name , rank FROM ranked_record WHERE name LIKE 'some name' 

Aktualisierung:

Nach John kommentiert, habe ich über den Fehler von Ansichten mit Variablen erkannt. Es ist nicht möglich, da die "feature/bug" of/from MySQL

Aufgrund dieser, Sie verwenden diese als subquery in FROM clause wählen:

SELECT 
    name, 
    rank 
FROM (
     SELECT 
      record.Name, 
      @curRank := @curRank + 1 AS rank 
     FROM 
      record, 
      (SELECT @curRank := 0) r 
    ) AS ranked_record 
WHERE 
    name LIKE 'some name'; 

OR eine Funktion erstellen, den Rang in der Ansicht zu zählen (like this example):

CREATE FUNCTION `func_inc_var_session`() RETURNS int(11) 
begin 
    SET @var := IFNULL(@var,0) + 1; 
    return @var; 

Ende;

Dann erstellen Sie Ihre Ansicht nach wie vor nur die Funktion anstelle der Variable:

CREATE VIEW ranked_record AS 
SELECT 
    record.Name, 
    func_inc_var_session() as rank 
FROM 
    record 
ORDER BY Record DESC; 
+0

@ AntonínLejsek Danke, kopieren und vergangenes Problem ... –

+0

Ich bekomme diesen Fehler: "# 1351 - Views SELECT enthält eine Variable oder Parameter" – John

+0

@John Mein Fehler, ich werde die Antwort mit der richtigen Version aktualisieren. –

-1

Ich verstehe nicht wirklich, warum Sie jeden Datensatz looping wissen, dass die Spalte "Name" ist es Ihre PK (eindeutige Werte).

$name="Darrin"; 
$query= mysqli_query($db_connection, "SELECT COUNT(1) as rank FROM record WHERE Name = '".mysqli_real_escape_string($name)."' ORDER BY Record DESC"); 

$row = mysqli_fetch_row($query); 
if ($query->num_rows > 0) { 
    echo "Rank : $row["rank"]<br>"; 
} 
+0

Dies ist ein schlechter Ansatz. Die Where-Klausel ist absolut der richtige Weg zu gehen, aber dies ist offen für SQL-Injektion. Dies muss eine parametrisierte Abfrage sein. –

+0

Danke für Ihren Kommentar. Können Sie einen Proof of Concept erstellen, der SQL-Code in diesen Satz einfügt? Ich denke, dass die Funktion mysql_real_escape_string diese Art von Angriff bereits verhindert. –

+0

Das eigentliche Problem ist, dass dies das Problem nicht löst, soweit ich das beurteilen kann. –

0

Wir können dies in SQL-Abfrage schreiben, anstatt die Datensätze zu holen und in PHP zu loopen.

select row = row_number() over(order by Record) , * from record where name like 'namex' 
+0

Das OP hat die Frage falsch markiert, es hat nichts mit ms sql server zu tun. Bitte entfernen Sie diese Antwort. – Shadow

+0

Gibt dies die richtige Zeilennummer? Oder gibt es immer "1"? –