简体   繁体   中英

Querying two tables using SQLAlchemy and PostgreSQL

I need help improving my SQLAlchemy query. I'm using Python 3.7, SQLAlchemy 1.3.15 and PosgresSQL 9.4.3 as database. I'm trying to return the count of appointments for a specific date and timeslot. However, my appointments and appointment slot tables are separate and I'm having to query both models/tables to get the desired results. Here's what I have;

Appointments Model

The appointment table have a few columns, which includes a foreign key to the appointment slots table.

class Appointment(ResourceMixin, db.Model): 
    __tablename__ = 'appointments'          

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id', onupdate='CASCADE', ondelete='CASCADE'), index=True, nullable=True)
    slot_id = db.Column(db.Integer, db.ForeignKey('appointment_slots.id', onupdate='CASCADE', ondelete='CASCADE'), index=True, nullable=False)
    appointment_date = db.Column(db.DateTime(), nullable=False)
    appointment_type = db.Column(db.String(128), nullable=False, default='general')

Appointment Slots Table

The appointment slots table contains the time slots for the appointments. The Model consist of a relationship back to the appointments table.

class AppointmentSlot(ResourceMixin, db.Model):                                                   
    __tablename__ = 'appointment_slots'                                                           
    id = db.Column(db.Integer, primary_key=True)                                                                         
    # Relationships.                                                                              
    appointments = db.relationship('Appointment', uselist=False,                                  
                                   backref='appointments', lazy='joined', passive_deletes=True)   
    start_time = db.Column(db.String(5), nullable=False, server_default='08:00')                                                                                             
    end_time = db.Column(db.String(5), nullable=False, server_default='17:00')                                      

SQLAlchemy Query

Currently I'm running the following SQLAlchemy query to get the appointment count for a specific date and time slot;

appointment_count = db.session.query(func.count(Appointment.id)).join(AppointmentSlot)\
        .filter(and_(Appointment.appointment_date == date, AppointmentSlot.id == Appointment.id,
                     AppointmentSlot.start_time == time)).scalar()

The query above return the correct results, which is a single digit value, but I'm worried that the query is not optimized. Currently the query returns in 380ms , but there's only 8 records in the appointments and appointment_slots tables. These tables will eventually have in the 100s of thousands of records. I'm worried that even though the query is working now that it will eventually struggle with an increase of records.

How can I improved or optimized this query to improve performance? I was looking at SQLAlchemy subqueries using the appointment relationship on the appointment_slots table, but was unable to get it to work and confirm the performance. I'm thinking there must be a better way to run this query especially using the appointments relationship on the appointment_slots table, but I'm currently stumped. Any suggestions?

I was incorrect about the query load time. I was actually looking at the page load that was 380ms. I also change the some fields on the models by removing the slot_id from the appointments model and adding a appointment_id foreign key to the appointment_slots model. The page load for the following query;

appointment_count = db.session.query(func.count(Appointment.id)).join(AppointmentSlot)\
        .filter(and_(Appointment.appointment_date == date, 
AppointmentSlot.appointment_id == Appointment.id, AppointmentSlot.start_time == time)).scalar()

ended up being; 0.4637ms .

However, I still tried to improve the query and was able to do so by using a SQLAlchemy subquery. The following subquery;

subquery = db.session.query(Appointment.id).filter(Appointment.appointment_date == date).subquery()
query = db.session.query(func.count(AppointmentSlot.id))\
        .filter(and_(AppointmentSlot.appointment_id.in_(subquery),
 AppointmentSlot.start_time == time)).scalar()

Return a load time of 0.3700ms which shows a much better performance than using the join query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM