avoid generate temporary table when query samples

Currently, when we call query-samples API, for SQL backend, we do
an inner join to get a temporary table, then apply filters, orderby
and limit options on it. Such implementation will drain disk space
or cause timeout exception when data set is growing, even with specified
limit and filters.

This patch applies filters and limit on the inner join itself, and
uses a fake mapper object instead of temporary table to suit current
query transformer.

Change-Id: I261a2dd362ed51c16a6fa191dadcce1b45fce2e4
Closes-Bug: #1506738
(cherry picked from commit b9bf5f1f57)
This commit is contained in:
ZhiQiang Fan 2015-10-16 02:45:45 -07:00
parent 5ccc0c06c0
commit 1cbe702e84
2 changed files with 34 additions and 25 deletions

View File

@ -603,7 +603,22 @@ class Connection(base.Connection):
session = self._engine_facade.get_session()
engine = self._engine_facade.get_engine()
query = session.query(models.FullSample)
query = session.query(models.Sample.timestamp,
models.Sample.recorded_at,
models.Sample.message_id,
models.Sample.message_signature,
models.Sample.volume.label('counter_volume'),
models.Meter.name.label('counter_name'),
models.Meter.type.label('counter_type'),
models.Meter.unit.label('counter_unit'),
models.Resource.source_id,
models.Resource.user_id,
models.Resource.project_id,
models.Resource.resource_metadata,
models.Resource.resource_id).join(
models.Meter, models.Meter.id == models.Sample.meter_id).join(
models.Resource,
models.Resource.internal_id == models.Sample.resource_id)
transformer = sql_utils.QueryTransformer(models.FullSample, query,
dialect=engine.dialect.name)
if filter_expr is not None:

View File

@ -20,7 +20,7 @@ from oslo_utils import timeutils
import six
from sqlalchemy import (Column, Integer, String, ForeignKey, Index,
UniqueConstraint, BigInteger)
from sqlalchemy import event, select
from sqlalchemy import event
from sqlalchemy import Float, Boolean, Text, DateTime
from sqlalchemy.dialects.mysql import DECIMAL
from sqlalchemy.ext.declarative import declarative_base
@ -221,29 +221,23 @@ class Sample(Base):
message_id = Column(String(1000))
class FullSample(Base):
"""Mapper model.
It's needed as many of the filters work against raw data which is split
between Meter, Sample, and Resource tables
"""
meter = Meter.__table__
sample = Sample.__table__
resource = Resource.__table__
__table__ = (select([sample.c.id, meter.c.name.label('counter_name'),
meter.c.type.label('counter_type'),
meter.c.unit.label('counter_unit'),
sample.c.volume.label('counter_volume'),
resource.c.resource_id, resource.c.source_id,
resource.c.user_id, resource.c.project_id,
resource.c.resource_metadata, resource.c.internal_id,
sample.c.timestamp, sample.c.message_id,
sample.c.message_signature, sample.c.recorded_at])
.select_from(
sample.join(meter, sample.c.meter_id == meter.c.id).join(
resource,
sample.c.resource_id == resource.c.internal_id))
.alias())
class FullSample(object):
"""A fake model for query samples."""
id = Sample.id
timestamp = Sample.timestamp
message_id = Sample.message_id
message_signature = Sample.message_signature
recorded_at = Sample.recorded_at
counter_name = Meter.name
counter_type = Meter.type
counter_unit = Meter.unit
counter_volume = Sample.volume
resource_id = Resource.resource_id
source_id = Resource.source_id
user_id = Resource.user_id
project_id = Resource.project_id
resource_metadata = Resource.resource_metadata
internal_id = Resource.internal_id
class Alarm(Base):