Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fotoanzeige/Fotoabruf optimiert: LIMIT ist zu langsam und selektiert …

…zuerst alles und schränkt erst als letztes ein!
  • Loading branch information...
commit 1a99e99b8ec4bd2ad6e07009c2c1e22636b97a5e 1 parent 0c858ae
@KyleRogers authored
View
10 app/model/Foto.scala
@@ -12,7 +12,8 @@ import net.sf.jmimemagic.{MagicMatchNotFoundException, Magic}
* @author Stefan Penndorf <stefan@cyphoria.net>
*/
case class Foto(id: Pk[Long] = NotAssigned,
- imageContent: mutable.WrappedArray[Byte] = new Array[Byte](11)) {
+ imageContent: mutable.WrappedArray[Byte],
+ position: Long) {
def mimeType = {
try {
@@ -32,8 +33,9 @@ object Foto {
val simple = {
get[Long]("fotos.id") ~
get[Long]("fotos.besitzer") ~
- bytes("fotos.foto") map {
- case id~besitzer~foto => Foto(Id(id), foto)
+ bytes("fotos.foto") ~
+ get[Int]("fotos.position") map {
+ case id~besitzer~foto~position => Foto(Id(id), foto, position)
}
}
@@ -53,7 +55,7 @@ object Foto {
DB.withConnection { implicit connection =>
SQL(
"""
- SELECT id,besitzer,foto FROM fotos WHERE id={id}
+ SELECT id,besitzer,foto,position FROM fotos WHERE id={id}
"""
).on(
'id -> id
View
54 app/model/Fotoalbum.scala
@@ -15,21 +15,20 @@ case class Fotoalbum(
anzahlFotos: Long
) {
- def fotoMitPosition(nummer: Long): Option[Foto] = {
- if(nummer < 1) {
+ def fotoMitPosition(position: Long): Option[Foto] = {
+ if(position < 1) {
None
} else {
DB.withConnection { implicit connection =>
SQL(
"""
- SELECT id,besitzer,foto FROM fotos f
- WHERE f.besitzer = {besitzerId}
- ORDER BY ID ASC
- LIMIT {idx},1
+ SELECT id,besitzer,foto,position FROM fotos f
+ WHERE f.besitzer = {besitzerId} AND
+ f.position = {position}
"""
).on(
'besitzerId -> besitzer.id,
- 'idx -> (nummer - 1)
+ 'position -> position
).as(Foto.simple.singleOpt)
}
}
@@ -37,47 +36,15 @@ case class Fotoalbum(
def naechstePosition(foto: Foto): Option[Long] = {
- val nextPos = positionVon(foto) + 1
+ val nextPos = foto.position + 1
fotoMitPosition(nextPos).map( _=> nextPos)
}
def vorhergehendePosition(foto: Foto): Option[Long] = {
- val prevPos = positionVon(foto) - 1
+ val prevPos = foto.position - 1
fotoMitPosition(prevPos).map( _=> prevPos)
}
-
- private def positionVon(foto: Foto): Long = {
- DB.withConnection { implicit connection =>
- SQL(
- """
- SELECT COUNT(*)+1 as cnt FROM fotos f
- WHERE f.besitzer = {besitzerId} AND
- f.id < {fotoId}
- """
- ).on(
- 'besitzerId -> besitzer.id,
- 'fotoId -> foto.id.get
- ).as(scalar[Long].single)
- }
- }
-
- lazy val erstesFoto: Foto = {
- DB.withConnection { implicit connection =>
- SQL(
- """
- SELECT id,besitzer,foto FROM fotos f
- WHERE f.besitzer = {besitzerId}
- ORDER BY ID ASC
- LIMIT 1
- """
- ).on(
- 'besitzerId -> besitzer.id
- ).as(Foto.simple.single)
- }
-
- }
-
}
object Fotoalbum {
@@ -126,9 +93,8 @@ class PersistenterFotoalbenVerwalter extends FotoalbenVerwalter {
DB.withConnection { implicit connection =>
SQL(
"""
- insert into fotos
- (besitzer, foto) values
- ({besitzerid}, {foto})
+ INSERT INTO fotos (besitzer, foto, position) VALUES
+ ( {besitzerid}, {foto}, (SELECT COUNT(*)+1 FROM fotos f2 WHERE f2.besitzer={besitzerid}) )
"""
).on(
'besitzerid -> besitzer.id,
View
15 conf/evolutions/default/5.sql
@@ -0,0 +1,15 @@
+# Neue Spalte für Sortierung der Fotos im Album
+
+# --- !Ups
+ALTER TABLE fotos
+ ADD COLUMN position INT NOT NULL DEFAULT '0';
+
+UPDATE `fotos` as f1 SET
+ f1.position = (Select count(*) from (SELECT * FROM fotos) as f2 where f1.besitzer=f2.besitzer AND f2.id<=f1.id );
+
+ALTER TABLE fotos
+ ALTER COLUMN position DROP DEFAULT;
+
+# --- !Downs
+ALTER TABLE fotos
+ DROP COLUMN position;
View
9 conf/evolutions/default/6.sql
@@ -0,0 +1,9 @@
+# Index für Sortierung der Fotos im Album
+
+# --- !Ups
+CREATE UNIQUE INDEX fotoalbum_reihenfolge
+ ON fotos (besitzer, position);
+
+
+# --- !Downs
+DROP INDEX fotoalbum_reihenfolge ON fotos;
View
11 test/net/cyphoria/weddingapp/model/FotoTest.scala
@@ -13,6 +13,7 @@ class FotoTest extends Specification {
val UNFUG_CONTENT: Array[Byte] = "\u00FF\u0034\u0056ABCDE".toCharArray.map(_.toByte)
val OTHER_CONTENT: Array[Byte] = "\u0012\u0034\u0056ABCDE".toCharArray.map(_.toByte)
+ val foto: Foto = Foto(Id(1), PNG_IMAGE_CONTENT, 1)
"Foto" should {
@@ -21,23 +22,23 @@ class FotoTest extends Specification {
}
"ein Foto finden, wenn ein Foto hochgeladen wurde" in DatenbankMit("einemGastMitEinemFoto") {
- Foto.findeMitId(1L) must beSome(Foto(Id(1), PNG_IMAGE_CONTENT))
+ Foto.findeMitId(1L) must beSome(foto)
}
"den korrekten Mime-Type für PNG bestimmen" in {
- Foto(imageContent = PNG_IMAGE_CONTENT).mimeType must beEqualTo("image/png")
+ Foto(imageContent = PNG_IMAGE_CONTENT, position = 1).mimeType must beEqualTo("image/png")
}
"den korrekten Mime-Type für JPEG bestimmen" in {
- Foto(imageContent = JPEG_IMAGE_CONTENT).mimeType must beEqualTo("image/jpeg")
+ Foto(imageContent = JPEG_IMAGE_CONTENT, position = 1).mimeType must beEqualTo("image/jpeg")
}
"einen anderen Mime-Type für ungültige Daten bestimmen" in {
- Foto(imageContent = OTHER_CONTENT).mimeType must not (beEqualTo("image/png") or beEqualTo("image/jpeg"))
+ Foto(imageContent = OTHER_CONTENT, position = 1).mimeType must not (beEqualTo("image/png") or beEqualTo("image/jpeg"))
}
"den Mime-Type 'application/octet-stream' bestimmen, wenn JMimeMagic keinen Treffer findet" in {
- Foto(imageContent = UNFUG_CONTENT).mimeType must beEqualTo("application/octet-stream")
+ Foto(imageContent = UNFUG_CONTENT, position = 1).mimeType must beEqualTo("application/octet-stream")
}
}
View
8 test/net/cyphoria/weddingapp/model/FotoalbumTest.scala
@@ -12,19 +12,17 @@ class FotoalbumTest extends Specification {
val einGast = KERSTIN
- val erstesFoto: Foto = Foto(Id(1), PNG_IMAGE_CONTENT)
- val zweitesFoto: Foto = Foto(Id(2), JPEG_IMAGE_CONTENT)
- val drittesFoto: Foto = Foto(Id(3), PNG_IMAGE_CONTENT)
+ val erstesFoto: Foto = Foto(Id(1), PNG_IMAGE_CONTENT, 1)
+ val zweitesFoto: Foto = Foto(Id(2), JPEG_IMAGE_CONTENT, 2)
+ val drittesFoto: Foto = Foto(Id(3), PNG_IMAGE_CONTENT, 3)
"Fotoalbum eines Gastes" should {
"das erste Foto zurück geben" in DatenbankMit("einemGastMitEinemFoto") {
- einGast.fotoalbum.get.erstesFoto must beEqualTo(erstesFoto)
einGast.fotoalbum.get.fotoMitPosition(1) must beSome(erstesFoto)
}
"das Foto mit der kleinsten ID als Foto mit Nummer 1 zurück geben, selbst wenn drei Fotos hochgeladen wurden" in DatenbankMit("einemGastMitDreiFotos") {
- einGast.fotoalbum.get.erstesFoto must beEqualTo(erstesFoto)
einGast.fotoalbum.get.fotoMitPosition(1) must beSome(erstesFoto)
}
View
2  test/net/cyphoria/weddingapp/templates/FotoTemplateTest.scala
@@ -13,7 +13,7 @@ import anorm.Id
class FotoTemplateTest extends Specification {
val foto = running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
- views.html.foto(Fotoalbum(TERESA, 1), Foto(Id(1)))
+ views.html.foto(Fotoalbum(TERESA, 1), Foto(Id(1), new Array[Byte](11), 1))
}
"Die Fotoansicht" should {
View
6 test/resources/model/einemGastMitDreiFotos.dbt
@@ -2,6 +2,6 @@ users:
- id: 1, email: "kerstin@cyphoria.net", vorname: "Kerstin", nachname: "Albert", passwort: "$2a$10$k5TmtHnitQvFCNAp8SbuFeq1VlhlcSGkXl6JAcwZFX20mRZKgEgm."
fotos:
-- id: 1, besitzer: 1, foto: "89504E470D0A1A0A4142434445"
-- id: 2, besitzer: 1, foto: "FFD8FFE000104A464946"
-- id: 3, besitzer: 1, foto: "89504E470D0A1A0A4142434445"
+- id: 1, besitzer: 1, foto: "89504E470D0A1A0A4142434445", position: 1
+- id: 2, besitzer: 1, foto: "FFD8FFE000104A464946", position: 2
+- id: 3, besitzer: 1, foto: "89504E470D0A1A0A4142434445", position: 3
View
2  test/resources/model/einemGastMitEinemFoto.dbt
@@ -2,4 +2,4 @@ users:
- id: 1, email: "kerstin@cyphoria.net", vorname: "Kerstin", nachname: "Albert", passwort: "$2a$10$k5TmtHnitQvFCNAp8SbuFeq1VlhlcSGkXl6JAcwZFX20mRZKgEgm."
fotos:
-- id: 1, besitzer: 1, foto: "89504E470D0A1A0A4142434445"
+- id: 1, besitzer: 1, foto: "89504E470D0A1A0A4142434445", position: 1
Please sign in to comment.
Something went wrong with that request. Please try again.