2016-03-23 13 views
1

Ich habe seit einiger Zeit mit dem Versuch zu kämpfen, Code für automatische Aggregationen in meiner MySQL/Mariadb-Datenbank zu generieren. Die Methode, die ich gerade versuche, verwendet Variablen. Ich werde im Voraus zugeben, dass ich kein Datenbankexperte bin. Ich bin völlig autodidaktisch und habe Mühe, angemessene Ressourcen für dieses spezielle Problem zu finden. Ich habe vereinfachte Beispiele unten, Oh, und ich verwende mariadb 10.1.Wie man Mysql-Variablen in einer Abfrage arbeiten lässt

Dieser Code sollte in mysql 5.6 sowie mariadb 10.0+ funktionieren, ich habe es auf 10.1 getestet und es funktioniert. Hier ist meine Tabelle: und SQL FIDDLE < - funktioniert aus irgendeinem Grund nicht. Wahrscheinlich die dynamischen Spalten. Ich werde es verlassen, falls jemand weiß warum.

CREATE TABLE data_points 
(
    id   BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    device_id INTEGER, 
    dtime  DATETIME, 
    sf   INTEGER(11), -- sample frequency or interval 
    agg   INTEGER(11), -- aggregation type, actually a fk 
    data_point BLOB, 
    PRIMARY KEY (id), 
    UNIQUE (device_id, dtime, sf, agg) 
); 

Hier können einige Daten einfügen:

INSERT INTO data_points 
    (device_id, dtime, sf, agg, data_point) 
VALUES 
    (1, '2015-01-02 12:00:00', 1, 60, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 13:00:00', 1, 60, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 14:00:00', 1, 60, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 15:00:00', 1, 60, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 16:00:00', 1, 60, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)); 

So bis zu diesem Punkt alles funktioniert gut. Ich versuche Aggregationen über verschiedene Zeiträume durchzuführen, meine niedrigste Kornperiode beträgt 60 Sekunden. Hier habe ich Probleme, es ist wahrscheinlich etwas offensichtlich.

SELECT 
    @dp_dtime := MAX(dtime), 
    @dp_aa := MIN(ROUND(COLUMN_GET(data_point, 'aa' AS DOUBLE), 4)), 
    @dp_ab := MIN(ROUND(COLUMN_GET(data_point, 'ab' AS DOUBLE), 4)), 
    @dp_ac := MIN(ROUND(COLUMN_GET(data_point, 'ac' AS DOUBLE), 4)) 
FROM data_points 
WHERE 
    device_id = 1 AND 
    dtime BETWEEN '2015/01/02 12:00:00' AND '2015/01/17 23:05:00' AND 
    sf = 60 AND 
    agg = 1; 

INSERT INTO data_points 
(device_id, dtime, sf, agg, data_point) 
VALUES (8, @dp_dtime, 300, 2, COLUMN_CREATE('aa', @dp_aa, 'ab', @dp_ab, 'ac', @dp_ac)); 

Dieser endet mit NULL weiteren Zeilen zu schaffen überall eine Variable in der Anweisung war.

select @dp_dtime, @dp_aa, @dp_ab, @pd_ac; 
-- This results in NULL, NULL, NULL, NULL 

An diesem Punkt bin ich ziemlich sicher, dass ich etwas falsch mit den Variablen mache. Es ist spät, 14 Stunden Tag. Bin ich sogar nah dran? Gibt es einen besseren/leichteren Weg? Jede Hilfe würde sehr geschätzt werden.

BEARBEITEN: In meinem realen Anwendungsfall hängt die Anzahl der Spalten von der Art des Geräts ab, für das eine Aggregation durchgeführt wurde. Spalten sind Excel-Stil 'aa' bis 'zz' möglich. obwohl das Maximum, das ich gesehen habe, ungefähr 150 Spalten breit ist. Das hört sich vielleicht nach einem schlechten Design an, aber die Performance ist überraschend, ich kann den Unterschied zwischen diesen dynamischen Spalten und tatsächlichen Spalten nicht erkennen. (mindestens so lange, wie Sie nicht auf sie indizieren müssen)

+0

Sie eine dynamische Abfrage erstellen, warum concat es nicht als String und verwenden vorbereitete Anweisung die Abfrage excute. –

+0

@RahulSingh Ich habe das an einem Punkt versucht und konnte es nicht zum Laufen bringen, ein Problem ist, in meinem realen Anwendungsfall kann die Anzahl der Spalten für jedes Gerät unterschiedlich sein. irgendwo zwischen 'aa' und 'zz' (Excel Stil Spalten). Ich werde morgens wieder in vorbereitete Stücke schauen. Danke für die schnelle Antwort. – bigjake

Antwort

1

Versuchen Sie die folgenden Abfragen.

SQL:

CREATE TABLE data_points 
(
    id   BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    device_id INTEGER, 
    dtime  DATETIME, 
    sf   INTEGER(11), -- sample frequency or interval 
    agg   INTEGER(11), -- aggregation type, actually a fk 
    data_point BLOB, 
    UNIQUE (device_id, dtime, sf, agg) 
); 
INSERT INTO data_points 
    (device_id, dtime, sf, agg, data_point) 
VALUES 
    (1, '2015-01-02 12:00:00', 1, 1, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 13:00:00', 1, 1, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 14:00:00', 1, 1, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 15:00:00', 1, 1, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)), 
    (1, '2015-01-02 16:00:00', 1, 1, COLUMN_CREATE('aa', 12, 'ab', 34, 'ac', 45)); 
select * from data_points; 
SELECT 
    @dp_dtime := MAX(dtime) as dp_dtime, 
    @dp_aa := MIN(ROUND(COLUMN_GET(data_point, 'aa' AS DOUBLE), 4)) as dp_aa, 
    @dp_ab := MIN(ROUND(COLUMN_GET(data_point, 'ab' AS DOUBLE), 4)) as dp_ab, 
    @dp_ac := MIN(ROUND(COLUMN_GET(data_point, 'ac' AS DOUBLE), 4)) as dp_ac 
FROM data_points 
WHERE 
    device_id = 1 AND 
    dtime BETWEEN '2015/01/02 12:00:00' AND '2015/1/17 23:05:00' AND 
    sf = 1 AND 
    agg = 1; 
INSERT INTO data_points 
(device_id, dtime, sf, agg, data_point) 
VALUES (8, @dp_dtime, 300, 2, COLUMN_CREATE('aa', @dp_aa, 'ab', @dp_ab, 'ac', @dp_ac)); 
select * from data_points; 

Ausgang:

mysql> select * from data_points; 
+----+-----------+---------------------+------+------+----------------------------+ 
| id | device_id | dtime    | sf | agg | data_point     | 
+----+-----------+---------------------+------+------+----------------------------+ 
| 1 |   1 | 2015-01-02 12:00:00 | 1 | 1 |   aaabacDZ | 
| 2 |   1 | 2015-01-02 13:00:00 | 1 | 1 |   aaabacDZ | 
| 3 |   1 | 2015-01-02 14:00:00 | 1 | 1 |   aaabacDZ | 
| 4 |   1 | 2015-01-02 15:00:00 | 1 | 1 |   aaabacDZ | 
| 5 |   1 | 2015-01-02 16:00:00 | 1 | 1 |   aaabacDZ | 
+----+-----------+---------------------+------+------+----------------------------+ 
5 rows in set (0.00 sec) 

mysql> SELECT 
    -> @dp_dtime := MAX(dtime) as dp_dtime, 
    -> @dp_aa := MIN(ROUND(COLUMN_GET(data_point, 'aa' AS DOUBLE), 4)) as dp_aa, 
    -> @dp_ab := MIN(ROUND(COLUMN_GET(data_point, 'ab' AS DOUBLE), 4)) as dp_ab, 
    -> @dp_ac := MIN(ROUND(COLUMN_GET(data_point, 'ac' AS DOUBLE), 4)) as dp_ac 
    -> FROM data_points 
    -> WHERE 
    -> device_id = 1 AND 
    -> dtime BETWEEN '2015/01/02 12:00:00' AND '2015/1/17 23:05:00' AND 
    -> sf = 1 AND 
    -> agg = 1; 
+---------------------+---------+---------+---------+ 
| dp_dtime   | dp_aa | dp_ab | dp_ac | 
+---------------------+---------+---------+---------+ 
| 2015-01-02 16:00:00 | 12.0000 | 34.0000 | 45.0000 | 
+---------------------+---------+---------+---------+ 
1 row in set (0.00 sec) 

mysql> INSERT INTO data_points 
    -> (device_id, dtime, sf, agg, data_point) 
    -> VALUES (8, @dp_dtime, 300, 2, COLUMN_CREATE('aa', @dp_aa, 'ab', @dp_ab, 'ac', @dp_ac)); 
Query OK, 1 row affected (0.00 sec) 

mysql> select * from data_points; 
+----+-----------+---------------------+------+------+-------------------------------------------------+ 
| id | device_id | dtime    | sf | agg | data_point          | 
+----+-----------+---------------------+------+------+-------------------------------------------------+ 
| 1 |   1 | 2015-01-02 12:00:00 | 1 | 1 |   aaabacDZ      | 
| 2 |   1 | 2015-01-02 13:00:00 | 1 | 1 |   aaabacDZ      | 
| 3 |   1 | 2015-01-02 14:00:00 | 1 | 1 |   aaabacDZ      | 
| 4 |   1 | 2015-01-02 15:00:00 | 1 | 1 |   aaabacDZ      | 
| 5 |   1 | 2015-01-02 16:00:00 | 1 | 1 |   aaabacDZ      | 
| 6 |   8 | 2015-01-02 16:00:00 | 300 | 2 |  ▒ aaabac  (@  [email protected][email protected] | 
+----+-----------+---------------------+------+------+-------------------------------------------------+ 
6 rows in set (0.00 sec) 
+0

Warum funktioniert das und nicht meins (abgesehen von den wenigen Bugs, die ich in meiner Frage behoben habe, wie eine SF von 60, die in der Tabelle nicht vorhanden war, ist es nur, weil du den Spalten Namen gegeben und sie zugewiesen hast Variablen? So oder so, das funktioniert, danke für das. Ich werde dies als akzeptiert markieren – bigjake

+0

Nun, jetzt bin ich gründlich verwirrt, sobald ich die Bedingungen in der Select-Anweisung behoben, Es funktionierte gut, vielleicht sollte ich aufhören zu arbeiten so spät ... nichtsdestoweniger führte mich deine Antwort zu meiner Lösung. Danke. – bigjake

+0

In deinem ursprünglichen Post gibt es einige Bugs. Nachdem sie repariert wurden, läuft es gut. '2015/00/17' war einer von ihnen. –

1

Möglicherweise ein einfacher Tippfehler: Ich sehe @_dtime.

Im UNIQUE Index, setzen Sie dtime zuletzt; Es wird die Abfragen schneller machen. Mini Index Lektion: Alle = Spalten sollten zuerst in einem zusammengesetzten Index, in beliebiger Reihenfolge (Kardinalität macht praktisch keinen Unterschied). Dann können Sie einen 'Bereich' (dtime) setzen. Alle Spalten nach einem Bereich werden nicht zum Filtern verwendet. Siehe my cookbook.

id loswerden und den UNIQUE Index zu PRIMARY KEY fördern; es wird die Abfragen noch schneller machen. Mini-Index Lektion: Sekundärschlüssel (wie Ihre UNIQUE) erfordert Bouncing zwischen dem Schlüssel und den Daten. Die PRIMARY KEY ist mit den Daten (in InnoDB) geclustert, wodurch das Prellen vermieden wird. Stattdessen ist ein 'Bereichsscan' über den PK ein Bereich über der Tabelle.

+0

Ja, der Tippfehler bestand darin, den falschen Code zu kopieren und einzufügen, alle Variablen, die mit _ statt mit dp_ beginnen. Ich dachte, vielleicht mochte es das nicht so, also habe ich es geändert. Immer noch läuft es damit nicht behoben. Die device_id filtert die meisten Zeilen heraus und der dtime Schlüssel hat tatsächlich die höchste Kardinalität aller Schlüssel. Ich hatte den Eindruck, dass dies für zusammengesetzte Indizes die richtige Reihenfolge für die höchste Geschwindigkeit war. Auch dieser Code läuft alle in einem Cluster, ich dachte, die Id wäre Pflicht, denn Knoten 1 verwendet 1,4,8, Knoten 2 verwendet 2,5,9 ... Dann wiederum, die einzigartige Schlüsselart besiegt den Punkt von diesem. – bigjake

+0

Whoa - Welche Art von Cluster. NDB? Galera? Andere? Dies kann kritisch für die Diskussion sein. –

+0

Ich habe auf die Indexierung Probleme ausgearbeitet. –

Verwandte Themen